@jd-data-limited/easy-fm 4.0.9 → 4.0.11
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 +1 -1
- package/src/connection/database.d.ts +1 -0
- package/src/connection/database.js +4 -0
- package/src/connection/database.ts +3 -0
- package/src/records/field.d.ts +25 -0
- package/src/records/field.js +165 -0
- package/src/records/fieldBase.d.ts +3 -3
- package/src/records/fieldBase.js +3 -3
- package/src/records/fieldBase.ts +5 -5
- package/src/records/getOperations/find.d.ts +15 -0
- package/src/records/getOperations/find.js +80 -0
- package/src/records/getOperations/recordGetOperation.d.ts +5 -4
- package/src/records/getOperations/recordGetOperation.js +8 -6
- package/src/records/getOperations/recordGetOperation.ts +8 -7
- package/src/records/getOperations/recordGetRange.d.ts +13 -0
- package/src/records/getOperations/recordGetRange.js +88 -0
- package/src/records/portalRecordBase.d.ts +4 -0
- package/src/records/portalRecordBase.js +6 -0
- package/src/types.d.ts +2 -1
- package/src/types.js +5 -5
- package/src/types.ts +3 -2
- package/src/bin/cli.d.ts +0 -2
- package/src/bin/cli.js +0 -19
- package/src/bin/example.xml +0 -0
- package/src/bin/generateTypes.d.ts +0 -1
- package/src/bin/generateTypes.js +0 -250
package/package.json
CHANGED
|
@@ -15,6 +15,7 @@ export declare class Database<T extends DatabaseStructure> extends EventEmitter
|
|
|
15
15
|
private connection_details;
|
|
16
16
|
private cookies;
|
|
17
17
|
readonly name: string;
|
|
18
|
+
readonly debug: boolean;
|
|
18
19
|
constructor(host: HostBase, conn: databaseOptionsWithExternalSources);
|
|
19
20
|
private generateExternalSourceLogin;
|
|
20
21
|
logout(): Promise<void>;
|
|
@@ -12,11 +12,13 @@ export class Database extends EventEmitter {
|
|
|
12
12
|
connection_details;
|
|
13
13
|
cookies = {};
|
|
14
14
|
name;
|
|
15
|
+
debug;
|
|
15
16
|
constructor(host, conn) {
|
|
16
17
|
super();
|
|
17
18
|
this.host = host;
|
|
18
19
|
this.name = conn.database;
|
|
19
20
|
this.connection_details = conn;
|
|
21
|
+
this.debug = !!conn.debug;
|
|
20
22
|
}
|
|
21
23
|
generateExternalSourceLogin(data) {
|
|
22
24
|
if (data.credentials.method === "filemaker") {
|
|
@@ -86,6 +88,8 @@ export class Database extends EventEmitter {
|
|
|
86
88
|
return `${this.host.hostname}/fmi/data/v2/databases/${this.name}`;
|
|
87
89
|
}
|
|
88
90
|
async apiRequestRaw(url, options = {}, autoRelogin = true) {
|
|
91
|
+
if (this.debug)
|
|
92
|
+
console.log(`EASYFM DEBUG: ${options.method?.toString().toUpperCase() || "GET"} ${url instanceof Request ? url.url : url}`);
|
|
89
93
|
if (!this.token)
|
|
90
94
|
await this.login(true);
|
|
91
95
|
if (!options.headers)
|
|
@@ -29,12 +29,14 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
|
|
|
29
29
|
private connection_details: databaseOptionsWithExternalSources
|
|
30
30
|
private cookies: { [key: string]: string } = {}
|
|
31
31
|
readonly name: string;
|
|
32
|
+
readonly debug: boolean
|
|
32
33
|
|
|
33
34
|
constructor(host: HostBase, conn: databaseOptionsWithExternalSources) {
|
|
34
35
|
super()
|
|
35
36
|
this.host = host
|
|
36
37
|
this.name = conn.database
|
|
37
38
|
this.connection_details = conn
|
|
39
|
+
this.debug = !!conn.debug
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
private generateExternalSourceLogin(data: databaseOptionsBase) {
|
|
@@ -111,6 +113,7 @@ export class Database<T extends DatabaseStructure> extends EventEmitter implemen
|
|
|
111
113
|
}
|
|
112
114
|
|
|
113
115
|
async apiRequestRaw(url: string | Request, options: any = {}, autoRelogin = true): Promise<Response> {
|
|
116
|
+
if (this.debug) console.log(`EASYFM DEBUG: ${options.method?.toString().toUpperCase() || "GET"} ${url instanceof Request ? url.url : url}`)
|
|
114
117
|
if (!this.token) await this.login(true)
|
|
115
118
|
|
|
116
119
|
if (!options.headers) options.headers = {}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
/// <reference types="node" />
|
|
3
|
+
import { RecordBase } from "./recordBase.js";
|
|
4
|
+
import * as http from "http";
|
|
5
|
+
import { ContainerBufferResult, DOWNLOAD_MODES } from "../types.js";
|
|
6
|
+
import { ApiFieldMetadata } from "../models/apiResults.js";
|
|
7
|
+
export type FieldValue = string | number | Date | Container;
|
|
8
|
+
export type Container = null;
|
|
9
|
+
export declare class Field<T extends FieldValue> {
|
|
10
|
+
record: RecordBase<any>;
|
|
11
|
+
id: string;
|
|
12
|
+
protected _value: T;
|
|
13
|
+
edited: boolean;
|
|
14
|
+
constructor(record: any, id: any, contents: any);
|
|
15
|
+
set(content: string | number | Date | undefined | null): void;
|
|
16
|
+
get metadata(): ApiFieldMetadata;
|
|
17
|
+
get value(): T;
|
|
18
|
+
set value(value: T);
|
|
19
|
+
get string(): string;
|
|
20
|
+
get date(): Date;
|
|
21
|
+
get number(): number;
|
|
22
|
+
upload(buffer: Buffer, filename: string, mime: string): Promise<void>;
|
|
23
|
+
download(mode: DOWNLOAD_MODES.Stream): Promise<http.IncomingMessage>;
|
|
24
|
+
download(mode: DOWNLOAD_MODES.Buffer): Promise<ContainerBufferResult>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023. See LICENSE file for more information
|
|
3
|
+
*/
|
|
4
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
5
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
6
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
7
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
8
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
9
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
10
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
import { RecordTypes } from "./recordBase.js";
|
|
14
|
+
import { File, FormData } from "node-fetch";
|
|
15
|
+
import { DOWNLOAD_MODES } from "../types.js";
|
|
16
|
+
import { ApiFieldDisplayTypes, ApiFieldResultTypes, ApiFieldTypes } from "../models/apiResults.js";
|
|
17
|
+
export class Field {
|
|
18
|
+
constructor(record, id, contents) {
|
|
19
|
+
this.record = record;
|
|
20
|
+
this.id = id;
|
|
21
|
+
this._value = contents;
|
|
22
|
+
this.edited = false;
|
|
23
|
+
}
|
|
24
|
+
set(content) {
|
|
25
|
+
if (this.metadata.result === "container")
|
|
26
|
+
throw "Cannot set container value using set(). Use upload() instead.";
|
|
27
|
+
if ((this.metadata.result === "timeStamp" ||
|
|
28
|
+
this.metadata.result === "date" ||
|
|
29
|
+
this.metadata.result === "time")
|
|
30
|
+
&& !(content instanceof Date) && !!content) {
|
|
31
|
+
throw "Value was not an instance of Date: " + content;
|
|
32
|
+
}
|
|
33
|
+
// @ts-ignore
|
|
34
|
+
if (!content)
|
|
35
|
+
this._value = "";
|
|
36
|
+
// @ts-ignore
|
|
37
|
+
else
|
|
38
|
+
this._value = content;
|
|
39
|
+
this.edited = true;
|
|
40
|
+
}
|
|
41
|
+
get metadata() {
|
|
42
|
+
if (!this.record.layout.metadata) {
|
|
43
|
+
// Default to a regular text field
|
|
44
|
+
return {
|
|
45
|
+
name: this.id.toString(),
|
|
46
|
+
type: ApiFieldTypes.NORMAL,
|
|
47
|
+
displayType: ApiFieldDisplayTypes.EDIT_TEXT,
|
|
48
|
+
result: ApiFieldResultTypes.TEXT,
|
|
49
|
+
global: false,
|
|
50
|
+
autoEnter: true,
|
|
51
|
+
fourDigitYear: false,
|
|
52
|
+
maxRepeat: 1,
|
|
53
|
+
maxCharacters: 0,
|
|
54
|
+
notEmpty: false,
|
|
55
|
+
numeric: false,
|
|
56
|
+
timeOfDay: false,
|
|
57
|
+
repetitions: 1,
|
|
58
|
+
valueList: ""
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
if (this.record.type === RecordTypes.PORTAL) {
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
return this.record.layout.metadata.portalMetaData[this.record.portal.name || "portal not attached"].find(i => i.name === this.id) || {
|
|
64
|
+
name: this.id.toString(),
|
|
65
|
+
type: 'normal',
|
|
66
|
+
displayType: 'editText',
|
|
67
|
+
result: 'text',
|
|
68
|
+
global: false,
|
|
69
|
+
autoEnter: true,
|
|
70
|
+
fourDigitYear: false,
|
|
71
|
+
maxRepeat: 1,
|
|
72
|
+
maxCharacters: 0,
|
|
73
|
+
notEmpty: false,
|
|
74
|
+
numeric: false,
|
|
75
|
+
timeOfDay: false,
|
|
76
|
+
repetitionStart: 1,
|
|
77
|
+
repetitionEnd: 1
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
return this.record.layout.metadata.fieldMetaData.find(i => i.name === this.id) || {
|
|
82
|
+
name: this.id.toString(),
|
|
83
|
+
type: ApiFieldTypes.NORMAL,
|
|
84
|
+
displayType: ApiFieldDisplayTypes.EDIT_TEXT,
|
|
85
|
+
result: ApiFieldResultTypes.TEXT,
|
|
86
|
+
global: false,
|
|
87
|
+
autoEnter: true,
|
|
88
|
+
fourDigitYear: false,
|
|
89
|
+
maxRepeat: 1,
|
|
90
|
+
maxCharacters: 0,
|
|
91
|
+
notEmpty: false,
|
|
92
|
+
numeric: false,
|
|
93
|
+
timeOfDay: false,
|
|
94
|
+
repetitions: 1,
|
|
95
|
+
valueList: ""
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
get value() {
|
|
100
|
+
// if (this.metadata.result === "container") throw "Use await field.stream() to get the contents of a container field, instead of field.value"
|
|
101
|
+
return this._value;
|
|
102
|
+
}
|
|
103
|
+
set value(value) {
|
|
104
|
+
this._value = value;
|
|
105
|
+
}
|
|
106
|
+
get string() {
|
|
107
|
+
if (typeof this._value === "string") {
|
|
108
|
+
return this._value;
|
|
109
|
+
}
|
|
110
|
+
throw "Field value is not a string";
|
|
111
|
+
}
|
|
112
|
+
get date() {
|
|
113
|
+
if (this._value instanceof Date) {
|
|
114
|
+
return this._value;
|
|
115
|
+
}
|
|
116
|
+
throw "Field value is not a date";
|
|
117
|
+
}
|
|
118
|
+
get number() {
|
|
119
|
+
if (typeof this._value === "number") {
|
|
120
|
+
return this._value;
|
|
121
|
+
}
|
|
122
|
+
throw "Field value is not a number";
|
|
123
|
+
}
|
|
124
|
+
upload(buffer, filename, mime) {
|
|
125
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
126
|
+
let trace = new Error();
|
|
127
|
+
if (this.metadata.result !== "container")
|
|
128
|
+
throw "Cannot upload a file to the field; " + this.id + " (not a container field)";
|
|
129
|
+
let form = new FormData();
|
|
130
|
+
form.append("upload", new File([buffer], filename, { type: mime }));
|
|
131
|
+
yield this.record.layout.database.apiRequest(`${this.record.endpoint}/containers/${this.id}/1`, {
|
|
132
|
+
method: "POST",
|
|
133
|
+
// @ts-ignore
|
|
134
|
+
headers: { "content-type": "multipart/form-data" },
|
|
135
|
+
body: form
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
download(mode = DOWNLOAD_MODES.Stream) {
|
|
140
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
141
|
+
if (this.metadata.result !== ApiFieldResultTypes.CONTAINER)
|
|
142
|
+
throw new Error("Cannot perform download() on a non-container field");
|
|
143
|
+
let stream = yield this.record.layout.database.streamURL(this.string);
|
|
144
|
+
if (mode === DOWNLOAD_MODES.Stream) {
|
|
145
|
+
return stream;
|
|
146
|
+
}
|
|
147
|
+
let body = [];
|
|
148
|
+
return new Promise((resolve, reject) => {
|
|
149
|
+
stream.on("data", chunk => {
|
|
150
|
+
body.push(chunk);
|
|
151
|
+
});
|
|
152
|
+
stream.on("error", (e) => {
|
|
153
|
+
reject(e);
|
|
154
|
+
});
|
|
155
|
+
stream.on("end", () => {
|
|
156
|
+
resolve({
|
|
157
|
+
buffer: Buffer.concat(body),
|
|
158
|
+
mime: stream.headers["content-type"],
|
|
159
|
+
request: stream
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" resolution-mode="require"/>
|
|
2
2
|
/// <reference types="node" resolution-mode="require"/>
|
|
3
3
|
import * as http from "http";
|
|
4
|
-
import { ContainerBufferResult,
|
|
4
|
+
import { ContainerBufferResult, DownloadModes, RecordTypes } from "../types.js";
|
|
5
5
|
import { ApiFieldMetadata } from "../models/apiResults.js";
|
|
6
6
|
import { LayoutBase } from "../layouts/layoutBase.js";
|
|
7
7
|
export type FieldValue = string | number | Date | Container;
|
|
@@ -25,6 +25,6 @@ export declare class FieldBase<T extends FieldValue> {
|
|
|
25
25
|
get date(): Date;
|
|
26
26
|
get number(): number;
|
|
27
27
|
upload(buffer: Buffer, filename: string, mime: string): Promise<void>;
|
|
28
|
-
download(mode:
|
|
29
|
-
download(mode:
|
|
28
|
+
download(mode: DownloadModes.Stream): Promise<http.IncomingMessage>;
|
|
29
|
+
download(mode: DownloadModes.Buffer): Promise<ContainerBufferResult>;
|
|
30
30
|
}
|
package/src/records/fieldBase.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright (c) 2023-2024. See LICENSE file for more information
|
|
3
3
|
*/
|
|
4
|
-
import {
|
|
4
|
+
import { DownloadModes, RecordTypes } from "../types.js";
|
|
5
5
|
import { ApiFieldDisplayTypes, ApiFieldResultTypes, ApiFieldTypes } from "../models/apiResults.js";
|
|
6
6
|
export class FieldBase {
|
|
7
7
|
parent;
|
|
@@ -128,11 +128,11 @@ export class FieldBase {
|
|
|
128
128
|
if (!res.ok)
|
|
129
129
|
throw new Error(`Upload failed with HTTP error: ${res.status} (${res.statusText})`);
|
|
130
130
|
}
|
|
131
|
-
async download(mode =
|
|
131
|
+
async download(mode = DownloadModes.Stream) {
|
|
132
132
|
if (this.metadata.result !== ApiFieldResultTypes.CONTAINER)
|
|
133
133
|
throw new Error("Cannot perform download() on a non-container field");
|
|
134
134
|
let stream = await this.parent.layout.database.streamURL(this.string);
|
|
135
|
-
if (mode ===
|
|
135
|
+
if (mode === DownloadModes.Stream) {
|
|
136
136
|
return stream;
|
|
137
137
|
}
|
|
138
138
|
let body = [];
|
package/src/records/fieldBase.ts
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import * as http from "http";
|
|
6
|
-
import {ContainerBufferResult,
|
|
6
|
+
import {ContainerBufferResult, DownloadModes, FieldMetaData, RecordTypes} from "../types.js";
|
|
7
7
|
import {ApiFieldDisplayTypes, ApiFieldMetadata, ApiFieldResultTypes, ApiFieldTypes} from "../models/apiResults.js";
|
|
8
8
|
import {LayoutBase} from "../layouts/layoutBase.js";
|
|
9
9
|
|
|
@@ -144,13 +144,13 @@ export class FieldBase<T extends FieldValue> {
|
|
|
144
144
|
if (!res.ok) throw new Error(`Upload failed with HTTP error: ${res.status} (${res.statusText})`)
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
download(mode:
|
|
148
|
-
download(mode:
|
|
149
|
-
async download(mode:
|
|
147
|
+
download(mode: DownloadModes.Stream): Promise<http.IncomingMessage>
|
|
148
|
+
download(mode: DownloadModes.Buffer): Promise<ContainerBufferResult>
|
|
149
|
+
async download(mode: DownloadModes = DownloadModes.Stream): Promise<http.IncomingMessage | ContainerBufferResult> {
|
|
150
150
|
if (this.metadata.result !== ApiFieldResultTypes.CONTAINER) throw new Error("Cannot perform download() on a non-container field")
|
|
151
151
|
|
|
152
152
|
let stream = await this.parent.layout.database.streamURL(this.string)
|
|
153
|
-
if (mode ===
|
|
153
|
+
if (mode === DownloadModes.Stream) {
|
|
154
154
|
return stream
|
|
155
155
|
}
|
|
156
156
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { RecordGetOperation } from "./recordGetOperation.js";
|
|
2
|
+
import { LayoutRecord } from "../layoutRecord.js";
|
|
3
|
+
import { LayoutInterface } from "../../layouts/layoutInterface";
|
|
4
|
+
import { LayoutBase } from "../../layouts/layoutBase.js";
|
|
5
|
+
export declare class Find<T extends LayoutInterface> extends RecordGetOperation<T> {
|
|
6
|
+
protected queries: object[];
|
|
7
|
+
constructor(layout: LayoutBase, start?: number, limit?: number);
|
|
8
|
+
private toObject;
|
|
9
|
+
addRequests(...requests: any[]): this;
|
|
10
|
+
/**
|
|
11
|
+
* @deprecated in favour of .fetch()
|
|
12
|
+
*/
|
|
13
|
+
run(): Promise<LayoutRecord<T["fields"], T["portals"]>[]>;
|
|
14
|
+
fetch(): Promise<LayoutRecord<T["fields"], T["portals"]>[]>;
|
|
15
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023. See LICENSE file for more information
|
|
3
|
+
*/
|
|
4
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
5
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
6
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
7
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
8
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
9
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
10
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
import { RecordGetOperation } from "./recordGetOperation.js";
|
|
14
|
+
import { LayoutRecord } from "../layoutRecord.js";
|
|
15
|
+
import { FMError } from "../../FMError.js";
|
|
16
|
+
export class Find extends RecordGetOperation {
|
|
17
|
+
constructor(layout, start = 0, limit = 100) {
|
|
18
|
+
super(layout);
|
|
19
|
+
this.setOffset(start);
|
|
20
|
+
this.setLimit(limit);
|
|
21
|
+
this.queries = [];
|
|
22
|
+
}
|
|
23
|
+
toObject() {
|
|
24
|
+
let out = { query: this.queries, sort: undefined };
|
|
25
|
+
if (this.sort.length !== 0)
|
|
26
|
+
out.sort = this.sort;
|
|
27
|
+
for (let item of Object.keys(this.scripts)) {
|
|
28
|
+
if (this.scripts[item]) {
|
|
29
|
+
out[item] = this.scripts[item].name;
|
|
30
|
+
if (this.scripts[item].parameter)
|
|
31
|
+
out[item + ".param"] = this.scripts[item].parameter;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
if (this.limit !== 100)
|
|
35
|
+
out["limit"] = this.limit;
|
|
36
|
+
if (this.offset !== 0)
|
|
37
|
+
out["offset"] = this.offset;
|
|
38
|
+
if (this.limitPortals.length > 0) {
|
|
39
|
+
out["portal"] = this.limitPortals.map(p => p.portalName);
|
|
40
|
+
for (let item of this.limitPortals) {
|
|
41
|
+
out["offset." + item.portalName.replace(/[^0-9A-z]/g, "")] = item.offset;
|
|
42
|
+
out["limit." + item.portalName.replace(/[^0-9A-z]/g, "")] = item.limit;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
addRequests(...requests) {
|
|
48
|
+
for (let item of requests)
|
|
49
|
+
this.queries.push(item);
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @deprecated in favour of .fetch()
|
|
54
|
+
*/
|
|
55
|
+
run() {
|
|
56
|
+
return this.fetch();
|
|
57
|
+
}
|
|
58
|
+
fetch() {
|
|
59
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
60
|
+
let trace = new Error();
|
|
61
|
+
yield this.layout.getLayoutMeta();
|
|
62
|
+
let res = yield this.layout.database.apiRequest(`${this.layout.endpoint}/_find`, {
|
|
63
|
+
port: 443,
|
|
64
|
+
method: "POST",
|
|
65
|
+
body: JSON.stringify(this.toObject())
|
|
66
|
+
});
|
|
67
|
+
if (res.messages[0].code === "0") {
|
|
68
|
+
// console.log("RESOLVING")
|
|
69
|
+
if (!this.layout.metadata)
|
|
70
|
+
yield this.layout.getLayoutMeta();
|
|
71
|
+
return res.response.data.map(item => {
|
|
72
|
+
return new LayoutRecord(this.layout, item.recordId, item.modId, item.fieldData, item.portalData);
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
throw new FMError(res.messages[0].code, res.httpStatus, res, trace);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -6,8 +6,6 @@ import { Query } from "../../utils/query.js";
|
|
|
6
6
|
export type SortOrder = "ascend" | "descend";
|
|
7
7
|
export type FindRequest = {
|
|
8
8
|
[key: string]: Query;
|
|
9
|
-
} & {
|
|
10
|
-
omit?: "true" | "false";
|
|
11
9
|
};
|
|
12
10
|
export type PortalRequest = {
|
|
13
11
|
name: string;
|
|
@@ -33,7 +31,10 @@ export declare class RecordGetOperation<T extends LayoutInterface, OPTIONS exten
|
|
|
33
31
|
}[];
|
|
34
32
|
protected portals: Partial<PortalData<T>>;
|
|
35
33
|
protected offset: number;
|
|
36
|
-
protected queries:
|
|
34
|
+
protected queries: {
|
|
35
|
+
req: FindRequest;
|
|
36
|
+
omit: boolean;
|
|
37
|
+
}[];
|
|
37
38
|
constructor(layout: LayoutBase, options: OPTIONS);
|
|
38
39
|
get isFindRequest(): boolean;
|
|
39
40
|
private formatQueries;
|
|
@@ -43,7 +44,7 @@ export declare class RecordGetOperation<T extends LayoutInterface, OPTIONS exten
|
|
|
43
44
|
protected generateParamsURL(offset: number, limit: number): URLSearchParams;
|
|
44
45
|
scripts(scripts: ScriptRequestData): this;
|
|
45
46
|
sort(fieldName: string, sortOrder: SortOrder): this;
|
|
46
|
-
addRequest(query: FindRequest): this;
|
|
47
|
+
addRequest(query: FindRequest, omit?: boolean): this;
|
|
47
48
|
fetch(): Promise<LayoutRecord<PickPortals<T, keyof OPTIONS["portals"]>>[]>;
|
|
48
49
|
private performFind;
|
|
49
50
|
[Symbol.asyncIterator](): {
|
|
@@ -25,13 +25,15 @@ export class RecordGetOperation {
|
|
|
25
25
|
formatQueries() {
|
|
26
26
|
return this.queries.map(query => {
|
|
27
27
|
let out = {};
|
|
28
|
-
for (let key of Object.keys(query)) {
|
|
29
|
-
if (query[key][FindRequestSymbol])
|
|
30
|
-
out[key] = query[key][FindRequestSymbol];
|
|
28
|
+
for (let key of Object.keys(query.req)) {
|
|
29
|
+
if (query.req[key][FindRequestSymbol])
|
|
30
|
+
out[key] = query.req[key][FindRequestSymbol];
|
|
31
31
|
else {
|
|
32
|
-
out[key] = query[key];
|
|
32
|
+
out[key] = query.req[key];
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
|
+
if (query.omit)
|
|
36
|
+
out.omit = "true";
|
|
35
37
|
return out;
|
|
36
38
|
});
|
|
37
39
|
}
|
|
@@ -99,8 +101,8 @@ export class RecordGetOperation {
|
|
|
99
101
|
this.sortData.push({ fieldName, sortOrder });
|
|
100
102
|
return this;
|
|
101
103
|
}
|
|
102
|
-
addRequest(query) {
|
|
103
|
-
this.queries.push(query);
|
|
104
|
+
addRequest(query, omit = false) {
|
|
105
|
+
this.queries.push({ req: query, omit });
|
|
104
106
|
return this;
|
|
105
107
|
}
|
|
106
108
|
fetch() {
|
|
@@ -13,7 +13,7 @@ import {FindRequestSymbol, Query} from "../../utils/query.js";
|
|
|
13
13
|
export type SortOrder = "ascend" | "descend"
|
|
14
14
|
export type FindRequest = {
|
|
15
15
|
[key: string]: Query
|
|
16
|
-
}
|
|
16
|
+
}
|
|
17
17
|
|
|
18
18
|
export type PortalRequest = {
|
|
19
19
|
name: string,
|
|
@@ -38,7 +38,7 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
|
|
|
38
38
|
protected sortData: { fieldName: string, sortOrder: SortOrder }[] = []
|
|
39
39
|
protected portals: Partial<PortalData<T>>
|
|
40
40
|
protected offset: number = 1
|
|
41
|
-
protected queries: FindRequest[] = []
|
|
41
|
+
protected queries: {req: FindRequest, omit: boolean}[] = []
|
|
42
42
|
|
|
43
43
|
constructor(layout: LayoutBase, options: OPTIONS) {
|
|
44
44
|
this.layout = layout
|
|
@@ -55,10 +55,11 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
|
|
|
55
55
|
private formatQueries() {
|
|
56
56
|
return this.queries.map(query => {
|
|
57
57
|
let out: any = {}
|
|
58
|
-
for (let key of Object.keys(query)) {
|
|
59
|
-
if (query[key][FindRequestSymbol]) out[key] = query[key][FindRequestSymbol]
|
|
60
|
-
else {out[key] = query[key]}
|
|
58
|
+
for (let key of Object.keys(query.req)) {
|
|
59
|
+
if (query.req[key][FindRequestSymbol]) out[key] = query.req[key][FindRequestSymbol]
|
|
60
|
+
else {out[key] = query.req[key]}
|
|
61
61
|
}
|
|
62
|
+
if (query.omit) out.omit = "true"
|
|
62
63
|
return out
|
|
63
64
|
})
|
|
64
65
|
}
|
|
@@ -127,8 +128,8 @@ export class RecordGetOperation<T extends LayoutInterface, OPTIONS extends GetOp
|
|
|
127
128
|
return this
|
|
128
129
|
}
|
|
129
130
|
|
|
130
|
-
addRequest(query: FindRequest) {
|
|
131
|
-
this.queries.push(query)
|
|
131
|
+
addRequest(query: FindRequest, omit = false) {
|
|
132
|
+
this.queries.push({req: query, omit})
|
|
132
133
|
return this
|
|
133
134
|
}
|
|
134
135
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { LayoutInterface } from "../../layouts/layoutInterface.js";
|
|
2
|
+
import { RecordGetOperation } from "./recordGetOperation.js";
|
|
3
|
+
import { LayoutRecord } from "../layoutRecord.js";
|
|
4
|
+
import { extraBodyOptions } from "../../types.js";
|
|
5
|
+
export declare class RecordGetRange<T extends LayoutInterface> extends RecordGetOperation<T> {
|
|
6
|
+
constructor(layout: any, start?: number, limit?: number);
|
|
7
|
+
private generateQueryParams;
|
|
8
|
+
/**
|
|
9
|
+
* @deprecated in favour of .fetch()
|
|
10
|
+
*/
|
|
11
|
+
run(extraBody?: extraBodyOptions): Promise<LayoutRecord<T["fields"], T["portals"]>[]>;
|
|
12
|
+
fetch(extraBody?: extraBodyOptions): Promise<LayoutRecord<T["fields"], T["portals"]>[]>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (c) 2023. See LICENSE file for more information
|
|
3
|
+
*/
|
|
4
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
5
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
6
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
7
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
8
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
9
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
10
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
11
|
+
});
|
|
12
|
+
};
|
|
13
|
+
import { RecordGetOperation } from "./recordGetOperation.js";
|
|
14
|
+
import { LayoutRecord } from "../layoutRecord.js";
|
|
15
|
+
import { FMError } from "../../FMError.js";
|
|
16
|
+
export class RecordGetRange extends RecordGetOperation {
|
|
17
|
+
constructor(layout, start = 0, limit = 100) {
|
|
18
|
+
super(layout);
|
|
19
|
+
this.setOffset(start);
|
|
20
|
+
this.setLimit(limit);
|
|
21
|
+
}
|
|
22
|
+
generateQueryParams(extraBody = {}) {
|
|
23
|
+
let params = [];
|
|
24
|
+
if (this.limit !== 100)
|
|
25
|
+
params.push("_limit=" + this.limit);
|
|
26
|
+
if (this.offset !== 0)
|
|
27
|
+
params.push("_offset=" + this.offset);
|
|
28
|
+
if (this.sort.length > 0)
|
|
29
|
+
params.push("_sort=" + encodeURI(JSON.stringify(this.sort)));
|
|
30
|
+
if (this.limitPortals.length > 0) {
|
|
31
|
+
params.push("portal=" + encodeURI(JSON.stringify(this.limitPortals.map(p => p.portalName))));
|
|
32
|
+
for (let item of this.limitPortals) {
|
|
33
|
+
if (item.offset !== 0)
|
|
34
|
+
params.push("_offset." + item.portalName.replace(/[^0-9A-z]/g, "") + "=" + item.offset);
|
|
35
|
+
if (item.limit !== 100)
|
|
36
|
+
params.push("_limit." + item.portalName.replace(/[^0-9A-z]/g, "") + "=" + item.limit);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (extraBody.scripts) {
|
|
40
|
+
if (extraBody.scripts.prerequest) {
|
|
41
|
+
params.push("script.prerequest=" + extraBody.scripts.prerequest.name);
|
|
42
|
+
if (extraBody.scripts.prerequest.parameter)
|
|
43
|
+
params.push("script.prerequest.param=" + extraBody.scripts.prerequest.parameter);
|
|
44
|
+
}
|
|
45
|
+
if (extraBody.scripts.presort) {
|
|
46
|
+
params.push("script.presort=" + extraBody.scripts.presort.name);
|
|
47
|
+
if (extraBody.scripts.presort.parameter)
|
|
48
|
+
params.push("script.presort.param=" + extraBody.scripts.presort.parameter);
|
|
49
|
+
}
|
|
50
|
+
if (extraBody.scripts.after) {
|
|
51
|
+
params.push("script=" + extraBody.scripts.after.name);
|
|
52
|
+
if (extraBody.scripts.after.parameter)
|
|
53
|
+
params.push("script.param=" + extraBody.scripts.after.parameter);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (params.length === 0)
|
|
57
|
+
return "";
|
|
58
|
+
return "?" + params.join("&");
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* @deprecated in favour of .fetch()
|
|
62
|
+
*/
|
|
63
|
+
run(extraBody = {}) {
|
|
64
|
+
return this.fetch(extraBody);
|
|
65
|
+
}
|
|
66
|
+
fetch(extraBody = {}) {
|
|
67
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
68
|
+
let trace = new Error();
|
|
69
|
+
let res = yield this.layout.getLayoutMeta().then(() => {
|
|
70
|
+
return this.layout.database.apiRequest(`${this.layout.endpoint}/records${this.generateQueryParams(extraBody)}`, {
|
|
71
|
+
method: "GET"
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
if (res.messages[0].code === "0") {
|
|
75
|
+
// console.log("RESOLVING")
|
|
76
|
+
if (!this.layout.metadata)
|
|
77
|
+
yield this.layout.getLayoutMeta();
|
|
78
|
+
let data = res.response.data.map(item => {
|
|
79
|
+
return new LayoutRecord(this.layout, item.recordId, item.modId, item.fieldData, item.portalData);
|
|
80
|
+
});
|
|
81
|
+
return data;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
throw new FMError(res.messages[0].code, res.httpStatus, res, trace);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/types.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export type PickPortals<LAYOUT extends LayoutInterface, PORTALS extends string |
|
|
|
8
8
|
};
|
|
9
9
|
export interface databaseOptionsBase {
|
|
10
10
|
database: string;
|
|
11
|
+
debug?: boolean;
|
|
11
12
|
credentials: loginOptionsOAuth | loginOptionsFileMaker | loginOptionsClaris | loginOptionsToken;
|
|
12
13
|
}
|
|
13
14
|
export interface databaseOptionsWithExternalSources extends databaseOptionsBase {
|
|
@@ -50,7 +51,7 @@ export type ScriptRequestData = {
|
|
|
50
51
|
export interface extraBodyOptions {
|
|
51
52
|
scripts?: ScriptRequestData;
|
|
52
53
|
}
|
|
53
|
-
export declare enum
|
|
54
|
+
export declare enum DownloadModes {
|
|
54
55
|
Stream = 0,
|
|
55
56
|
Buffer = 1
|
|
56
57
|
}
|
package/src/types.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* Copyright (c) 2022-2024. See LICENSE file for more information
|
|
3
3
|
*/
|
|
4
|
-
export var
|
|
5
|
-
(function (
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
})(
|
|
4
|
+
export var DownloadModes;
|
|
5
|
+
(function (DownloadModes) {
|
|
6
|
+
DownloadModes[DownloadModes["Stream"] = 0] = "Stream";
|
|
7
|
+
DownloadModes[DownloadModes["Buffer"] = 1] = "Buffer";
|
|
8
|
+
})(DownloadModes || (DownloadModes = {}));
|
|
9
9
|
export var RecordTypes;
|
|
10
10
|
(function (RecordTypes) {
|
|
11
11
|
RecordTypes[RecordTypes["UNKNOWN"] = 0] = "UNKNOWN";
|
package/src/types.ts
CHANGED
|
@@ -12,7 +12,8 @@ export type PickPortals<LAYOUT extends LayoutInterface, PORTALS extends string |
|
|
|
12
12
|
Omit<LAYOUT, "portals"> & { portals: Pick<LAYOUT["portals"], PORTALS> }
|
|
13
13
|
|
|
14
14
|
export interface databaseOptionsBase {
|
|
15
|
-
database: string
|
|
15
|
+
database: string,
|
|
16
|
+
debug?: boolean,
|
|
16
17
|
credentials: loginOptionsOAuth | loginOptionsFileMaker | loginOptionsClaris | loginOptionsToken,
|
|
17
18
|
}
|
|
18
19
|
|
|
@@ -64,7 +65,7 @@ export interface extraBodyOptions {
|
|
|
64
65
|
scripts?: ScriptRequestData
|
|
65
66
|
}
|
|
66
67
|
|
|
67
|
-
export enum
|
|
68
|
+
export enum DownloadModes {
|
|
68
69
|
Stream,
|
|
69
70
|
Buffer
|
|
70
71
|
}
|
package/src/bin/cli.d.ts
DELETED
package/src/bin/cli.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
"use strict";
|
|
3
|
-
/*
|
|
4
|
-
* Copyright (c) 2024. See LICENSE file for more information
|
|
5
|
-
*/
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
var commander_1 = require("commander");
|
|
8
|
-
var generateTypes_js_1 = require("./generateTypes.js");
|
|
9
|
-
var program = new commander_1.Command();
|
|
10
|
-
program
|
|
11
|
-
.name("easyfm")
|
|
12
|
-
.description("A NodeJS wrapper for the FileMaker Data CLI");
|
|
13
|
-
program
|
|
14
|
-
.command("generate-types")
|
|
15
|
-
.description("Automatically generate layout interfaces from your database")
|
|
16
|
-
.action(function () {
|
|
17
|
-
(0, generateTypes_js_1.generateTypesCLI)();
|
|
18
|
-
});
|
|
19
|
-
program.parse(process.argv);
|
package/src/bin/example.xml
DELETED
|
Binary file
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function generateTypesCLI(): Promise<void>;
|
package/src/bin/generateTypes.js
DELETED
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/*
|
|
3
|
-
* Copyright (c) 2024. See LICENSE file for more information
|
|
4
|
-
*/
|
|
5
|
-
var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cooked, raw) {
|
|
6
|
-
if (Object.defineProperty) { Object.defineProperty(cooked, "raw", { value: raw }); } else { cooked.raw = raw; }
|
|
7
|
-
return cooked;
|
|
8
|
-
};
|
|
9
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
10
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
11
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
12
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
13
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
14
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
15
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
19
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
20
|
-
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
21
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
22
|
-
function step(op) {
|
|
23
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
24
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
25
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
26
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
27
|
-
switch (op[0]) {
|
|
28
|
-
case 0: case 1: t = op; break;
|
|
29
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
30
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
31
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
32
|
-
default:
|
|
33
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
34
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
35
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
36
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
37
|
-
if (t[2]) _.ops.pop();
|
|
38
|
-
_.trys.pop(); continue;
|
|
39
|
-
}
|
|
40
|
-
op = body.call(thisArg, _);
|
|
41
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
42
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
46
|
-
exports.generateTypesCLI = void 0;
|
|
47
|
-
var apiResults_js_1 = require("../models/apiResults.js");
|
|
48
|
-
var inquirer_1 = require("inquirer");
|
|
49
|
-
var FMHost_js_1 = require("../connection/FMHost.js");
|
|
50
|
-
var fs = require("fs");
|
|
51
|
-
function sub(str) {
|
|
52
|
-
return str
|
|
53
|
-
.replace(/[^a-zA-Z0-9_]/g, "") // Remove non-alphanumeric characters
|
|
54
|
-
.replace(/^[0-9]+/g, ''); // Removing leading numbers
|
|
55
|
-
}
|
|
56
|
-
function generateFieldType(field) {
|
|
57
|
-
switch (field.result) {
|
|
58
|
-
case apiResults_js_1.ApiFieldResultTypes.TEXT:
|
|
59
|
-
return "FieldBase<string>";
|
|
60
|
-
case apiResults_js_1.ApiFieldResultTypes.CONTAINER:
|
|
61
|
-
return "FieldBase<Container>";
|
|
62
|
-
case apiResults_js_1.ApiFieldResultTypes.DATE:
|
|
63
|
-
return "FieldBase<Date>";
|
|
64
|
-
case apiResults_js_1.ApiFieldResultTypes.NUMBER:
|
|
65
|
-
return "FieldBase<number>";
|
|
66
|
-
case apiResults_js_1.ApiFieldResultTypes.TIME:
|
|
67
|
-
return "FieldBase<Date>";
|
|
68
|
-
case apiResults_js_1.ApiFieldResultTypes.TIMESTAMP:
|
|
69
|
-
return "FieldBase<Date>";
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function processFieldsChunk(fields) {
|
|
73
|
-
var existing_fields = [];
|
|
74
|
-
fields = fields.filter(function (field) {
|
|
75
|
-
if (existing_fields.includes(field.name))
|
|
76
|
-
return false;
|
|
77
|
-
existing_fields.push(field.name);
|
|
78
|
-
return true;
|
|
79
|
-
});
|
|
80
|
-
return fields.map(function (field) {
|
|
81
|
-
return JSON.stringify(field.name) + ": " + generateFieldType(field);
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
function camelToSnakeCase(str) {
|
|
85
|
-
return str.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
|
|
86
|
-
}
|
|
87
|
-
function safeStringInjection(str) {
|
|
88
|
-
var args = [];
|
|
89
|
-
for (var _i = 1; _i < arguments.length; _i++) {
|
|
90
|
-
args[_i - 1] = arguments[_i];
|
|
91
|
-
}
|
|
92
|
-
var result = "";
|
|
93
|
-
for (var i = 0; i < str.length; i++) {
|
|
94
|
-
result += str[i];
|
|
95
|
-
if (i < args.length) {
|
|
96
|
-
result += JSON.stringify(args[i].toString());
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return result;
|
|
100
|
-
}
|
|
101
|
-
function generateTypesCLI() {
|
|
102
|
-
return __awaiter(this, void 0, void 0, function () {
|
|
103
|
-
var data, HOST, DATABASE, stream, layouts, layoutInterfaces, _loop_1, _i, layouts_1, layout, layoutInterfaceLinks, _a, layoutInterfaces_1, layout, _b, layoutInterfaces_2, layout;
|
|
104
|
-
return __generator(this, function (_c) {
|
|
105
|
-
switch (_c.label) {
|
|
106
|
-
case 0:
|
|
107
|
-
process.stdout.write('\x1Bc');
|
|
108
|
-
console.log("For this tool to work, you are required to have access to an account on the target database.\n" +
|
|
109
|
-
"This account must have the fmrest extended privilege enabled.\n" +
|
|
110
|
-
"This tool can only export type interfaces for layouts that the given account has access to.");
|
|
111
|
-
console.log("\n");
|
|
112
|
-
return [4 /*yield*/, inquirer_1.default.prompt([
|
|
113
|
-
{
|
|
114
|
-
type: "input",
|
|
115
|
-
name: "hostname",
|
|
116
|
-
message: "The IP address/domain of your FileMaker server (must start with either http:// or https://)",
|
|
117
|
-
validate: function (input) {
|
|
118
|
-
return input.startsWith("http://") || input.startsWith("https://") || "Please enter a valid IP address/domain starting with http:// or https://";
|
|
119
|
-
}
|
|
120
|
-
},
|
|
121
|
-
{
|
|
122
|
-
type: "number",
|
|
123
|
-
name: "timezoneOffset",
|
|
124
|
-
message: "Server timezone offset (minutes)",
|
|
125
|
-
default: 0 - (new Date()).getTimezoneOffset()
|
|
126
|
-
},
|
|
127
|
-
{
|
|
128
|
-
type: "confirm",
|
|
129
|
-
name: "verify",
|
|
130
|
-
default: true,
|
|
131
|
-
message: "Verify your server's identity",
|
|
132
|
-
when: function (previousAnswers) {
|
|
133
|
-
return previousAnswers.hostname.startsWith("https://");
|
|
134
|
-
}
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
type: "input",
|
|
138
|
-
name: "database",
|
|
139
|
-
message: "Database filename"
|
|
140
|
-
},
|
|
141
|
-
{
|
|
142
|
-
type: "input",
|
|
143
|
-
name: "username",
|
|
144
|
-
message: "Database username"
|
|
145
|
-
},
|
|
146
|
-
{
|
|
147
|
-
type: "password",
|
|
148
|
-
name: "password",
|
|
149
|
-
message: "Database password",
|
|
150
|
-
mask: "*"
|
|
151
|
-
}
|
|
152
|
-
])];
|
|
153
|
-
case 1:
|
|
154
|
-
data = _c.sent();
|
|
155
|
-
HOST = new FMHost_js_1.default(data.hostname, data.timezoneOffset, data.verify);
|
|
156
|
-
DATABASE = HOST.database({
|
|
157
|
-
database: data.database,
|
|
158
|
-
credentials: {
|
|
159
|
-
method: "filemaker",
|
|
160
|
-
username: data.username,
|
|
161
|
-
password: data.password
|
|
162
|
-
},
|
|
163
|
-
externalSources: []
|
|
164
|
-
});
|
|
165
|
-
return [4 /*yield*/, DATABASE.login()
|
|
166
|
-
// Create file write stream
|
|
167
|
-
];
|
|
168
|
-
case 2:
|
|
169
|
-
_c.sent();
|
|
170
|
-
stream = fs.createWriteStream("./types.ts");
|
|
171
|
-
return [4 /*yield*/, DATABASE.listLayouts()];
|
|
172
|
-
case 3:
|
|
173
|
-
layouts = _c.sent();
|
|
174
|
-
stream.write("import FMHost, {Container, FieldBase, LayoutInterface, Portal} from \"@jd-data-limited/easy-fm\";\n");
|
|
175
|
-
stream.write("// " + layouts.length + " layouts found\n\n");
|
|
176
|
-
layoutInterfaces = new Map();
|
|
177
|
-
_loop_1 = function (layout) {
|
|
178
|
-
var metadata, fields, portals, portalsProcessed, interfaceName;
|
|
179
|
-
return __generator(this, function (_d) {
|
|
180
|
-
switch (_d.label) {
|
|
181
|
-
case 0: return [4 /*yield*/, layout.getLayoutMeta()];
|
|
182
|
-
case 1:
|
|
183
|
-
metadata = _d.sent();
|
|
184
|
-
fields = processFieldsChunk(metadata.fieldMetaData);
|
|
185
|
-
portals = metadata.portalMetaData;
|
|
186
|
-
portalsProcessed = Object.keys(portals).map(function (portalName) {
|
|
187
|
-
return "".concat(JSON.stringify(portalName), ": Portal<{").concat(processFieldsChunk(portals[portalName]), "}>");
|
|
188
|
-
});
|
|
189
|
-
interfaceName = sub(layout.name) + "LayoutInterface";
|
|
190
|
-
layoutInterfaces.set(layout.name, {
|
|
191
|
-
interfaceName: interfaceName,
|
|
192
|
-
interface: "export interface ".concat(interfaceName, " extends LayoutInterface {\n fields: {").concat(fields.join(",\n "), "},\n portals: {").concat(portalsProcessed.join(",\n "), "}\n }")
|
|
193
|
-
});
|
|
194
|
-
return [2 /*return*/];
|
|
195
|
-
}
|
|
196
|
-
});
|
|
197
|
-
};
|
|
198
|
-
_i = 0, layouts_1 = layouts;
|
|
199
|
-
_c.label = 4;
|
|
200
|
-
case 4:
|
|
201
|
-
if (!(_i < layouts_1.length)) return [3 /*break*/, 7];
|
|
202
|
-
layout = layouts_1[_i];
|
|
203
|
-
return [5 /*yield**/, _loop_1(layout)];
|
|
204
|
-
case 5:
|
|
205
|
-
_c.sent();
|
|
206
|
-
_c.label = 6;
|
|
207
|
-
case 6:
|
|
208
|
-
_i++;
|
|
209
|
-
return [3 /*break*/, 4];
|
|
210
|
-
case 7:
|
|
211
|
-
layoutInterfaceLinks = [];
|
|
212
|
-
for (_a = 0, layoutInterfaces_1 = layoutInterfaces; _a < layoutInterfaces_1.length; _a++) {
|
|
213
|
-
layout = layoutInterfaces_1[_a];
|
|
214
|
-
layoutInterfaceLinks.push([
|
|
215
|
-
"".concat(JSON.stringify(layout[0]), ": ").concat(layout[1].interfaceName),
|
|
216
|
-
"".concat(sub(camelToSnakeCase(layout[0]).toUpperCase().replace(" ", "_")), ": HOST.getLayout<").concat(layout[1].interfaceName, ">(").concat(JSON.stringify(layout[0]), ")")
|
|
217
|
-
]);
|
|
218
|
-
}
|
|
219
|
-
stream.write(safeStringInjection(templateObject_1 || (templateObject_1 = __makeTemplateObject(["const HOST = new FMHost(", ", ", ", ", ");"], ["const HOST = new FMHost(", ", ", ", ", ");"])), data.hostname, data.timezoneOffset, data.verify));
|
|
220
|
-
stream.write("HOST.database<{layouts:{".concat(layoutInterfaceLinks.map(function (i) { return i[0]; }).join(","), "}}>();"));
|
|
221
|
-
stream.write("\n\n");
|
|
222
|
-
stream.write("const LAYOUTS = {".concat(layoutInterfaceLinks.map(function (i) { return i[1]; }).join(","), "};"));
|
|
223
|
-
for (_b = 0, layoutInterfaces_2 = layoutInterfaces; _b < layoutInterfaces_2.length; _b++) {
|
|
224
|
-
layout = layoutInterfaces_2[_b];
|
|
225
|
-
stream.write("\n\n");
|
|
226
|
-
stream.write(layout[1].interface + ";");
|
|
227
|
-
}
|
|
228
|
-
// StructureKind
|
|
229
|
-
//
|
|
230
|
-
// const project = new Project({
|
|
231
|
-
// tsConfigFilePath: "../tsconfig.json"
|
|
232
|
-
// })
|
|
233
|
-
// project.resolveSourceFileDependencies()
|
|
234
|
-
return [4 /*yield*/, DATABASE.logout()];
|
|
235
|
-
case 8:
|
|
236
|
-
// StructureKind
|
|
237
|
-
//
|
|
238
|
-
// const project = new Project({
|
|
239
|
-
// tsConfigFilePath: "../tsconfig.json"
|
|
240
|
-
// })
|
|
241
|
-
// project.resolveSourceFileDependencies()
|
|
242
|
-
_c.sent();
|
|
243
|
-
console.log("DONE! Wrote database types to ./types.ts");
|
|
244
|
-
return [2 /*return*/];
|
|
245
|
-
}
|
|
246
|
-
});
|
|
247
|
-
});
|
|
248
|
-
}
|
|
249
|
-
exports.generateTypesCLI = generateTypesCLI;
|
|
250
|
-
var templateObject_1;
|