okai 0.0.28 → 0.0.30

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/api.d.ts CHANGED
@@ -1,4 +1,61 @@
1
1
  declare global {
2
+ export class bool {}
3
+ export class byte {} export class Byte {}
4
+ export class sbyte {} export class SByte {}
5
+ export class char {} export class Char {}
6
+ export class decimal {} export class Decimal {}
7
+ export class double {} export class Double {}
8
+ export class float {} export class Single {}
9
+ export class int {} export class Int32 {}
10
+ export class uint {} export class UInt32 {}
11
+ export class nint {} export class IntPtr {}
12
+ export class nuint {} export class UIntPtr {}
13
+ export class long {} export class Int64 {}
14
+ export class ulong {} export class UInt64 {}
15
+ export class short {} export class Int16 {}
16
+ export class ushort {} export class UInt16 {}
17
+ export class dynamic {} export class Dynamic {}
18
+ export class DateTime {}
19
+ export class TimeSpan {}
20
+ export class DateOnly {}
21
+ export class TimeOnly {}
22
+ export class Guid {}
23
+ export class List<T> {}
24
+ export class HashSet<T> {}
25
+ export class Dictionary<Key,Value> {}
26
+ export class Color {}
27
+
28
+ export interface IReturn<T> {}
29
+ export interface IReturnVoid {}
30
+
31
+ export interface IGet {}
32
+ export interface IPost {}
33
+ export interface IPut {}
34
+ export interface IPatch {}
35
+ export interface IDelete {}
36
+ export interface IOptions {}
37
+
38
+ export interface ICreateDb<Table> {}
39
+ export interface IPatchDb<Table> {}
40
+ export interface IUpdateDb<Table> {}
41
+ export interface IDeleteDb<Table> {}
42
+ export class QueryDb<T> extends QueryBase {}
43
+ export class QueryDb2<From,Into> extends QueryBase {}
44
+ export class QueryBase {}
45
+
46
+ export interface IHasSessionId {}
47
+ export interface IHasBearerToken {}
48
+
49
+ export class EmptyResponse {}
50
+ export class IdResponse {}
51
+ export class StringsResponse {}
52
+ export class StringResponse {}
53
+ export class IntResponse {}
54
+ export class BoolResponse {}
55
+ export class ErrorResponse {}
56
+ export class ResponseError {}
57
+ export class ResponseStatus {}
58
+
2
59
  export class AuditBase {
3
60
  createdDate: Date
4
61
  createdBy: string
@@ -20,9 +77,9 @@ declare global {
20
77
  }
21
78
 
22
79
  export type TypeOf = `typeof(${string})`
23
- export type InputAttrOptions = { type?:string, value?:string, placeholder?:string, help?:string, label?:string, title?:string, size?:string,
24
- pattern?:string, readOnly?:boolean, required?:boolean, disabled?:boolean, autocomplete?:string, autofocus?:string,
25
- min?:string, max?:string, step?:string, minLength?:number, maxLength?:number, accept?:string, capture?:string, multiple?:boolean,
80
+ export type InputAttrOptions = { type?:string, value?:string, placeholder?:string, help?:string, label?:string, title?:string, size?:string,
81
+ pattern?:string, readOnly?:boolean, required?:boolean, disabled?:boolean, autocomplete?:string, autofocus?:string,
82
+ min?:string, max?:string, step?:string, minLength?:number, maxLength?:number, accept?:string, capture?:string, multiple?:boolean,
26
83
  allowableValues?:string[], allowableValuesEnum?:TypeOf, options?:string, ignore?:boolean, evalAllowableValues?:string, evalAllowableEntries?:string, }
27
84
  export type ScriptValueOptions = { value?: any, expression?: string, eval?: string, noCache?: boolean }
28
85
 
@@ -52,7 +109,7 @@ declare global {
52
109
  export function validateHasClaim(claim:string) : ClassDecoratorDef
53
110
  export function validateHasScope(scope:string) : ClassDecoratorDef
54
111
  export function validateApiKey(scope?:string) : ClassDecoratorDef
55
-
112
+
56
113
  export function schema(schema:string) : ClassDecoratorDef
57
114
  export function compositeKey(columns:string[]) : ClassDecoratorDef
58
115
  export function compositeIndex(unique:boolean, columns:string[]) : ClassDecoratorDef
@@ -60,24 +117,28 @@ declare global {
60
117
  export function preDropTable(sql:string) : ClassDecoratorDef
61
118
  export function postCreateTable(sql:string) : ClassDecoratorDef
62
119
  export function postDropTable(sql:string) : ClassDecoratorDef
63
-
120
+
64
121
  export function api(description:string, opt?:{ bodyParameter?:number, requestContentType?:string, isRequired?:boolean }) : ClassDecoratorDef
65
122
  export function apiResponse(statusCode:number, description:string, opt?:{ isDefaultResponse?:boolean, responseType?:TypeOf }) : ClassDecoratorDef
66
-
123
+
67
124
  export function dataContract() : ClassDecoratorDef
68
- export function route(path:string, opt?:{ summary?:string, notes?:string, verbs?:string, priority?:number, matches?:string, }) : ClassDecoratorDef
125
+ export function route(path:string, opt?:{ summary?:string, notes?:string, verbs?:string, priority?:number, matches?:string, }|string) : ClassDecoratorDef
69
126
  export function icon(opt?:{ svg?:string, uri?:string, alt?:string, cls?:string, }) : ClassDecoratorDef
70
127
  export function field(opt?:InputAttrOptions & { name?:string, fieldCss?:string, inputCss?:string, labelCss?:string, }) : ClassDecoratorDef
71
128
  export function tag(name:string) : ClassDecoratorDef
72
129
  export function worker(name:string) : ClassDecoratorDef
73
130
  export function notes(notes:string) : ClassDecoratorDef
74
131
  export function namedConnection(name:string) : ClassDecoratorDef
75
-
132
+ export function explorerCss(opt?:{ form?:string, fieldset?:string, field?:string, }) : ClassDecoratorDef
133
+ export function locodeCss(opt?:{ form?:string, fieldset?:string, field?:string, }) : ClassDecoratorDef
134
+
76
135
  export enum QueryTerm { Default = 0, And = 1, Or = 2, Ensure = 3, }
77
136
  export function queryDb(defaultTerm:QueryTerm) : ClassDecoratorDef
78
137
  export function queryData(defaultTerm:QueryTerm) : ClassDecoratorDef
79
138
  export function autoFilter(term:QueryTerm, field?:string, opt?:{ operand?:string, template?:string, valueFormat:string }) : ClassDecoratorDef
80
139
  export function autoPopulate(field?:string, opt?:ScriptValueOptions) : ClassDecoratorDef
140
+ export function autoApply(name:string|Behavior, args?:string[]) : ClassDecoratorDef
141
+
81
142
  export class SqlTemplate {
82
143
  static IsNull: string
83
144
  static IsNotNull: string
@@ -89,15 +150,23 @@ declare global {
89
150
  static CaseSensitiveLike: string
90
151
  static CaseInsensitiveLike: string
91
152
  }
153
+ export enum Behavior {
154
+ AuditQuery,
155
+ AuditCreate,
156
+ AuditModify,
157
+ AuditDelete,
158
+ AuditSoftDelete,
159
+ }
92
160
 
93
161
  export function alias(table:string) : ClassOrFieldDecoratorDef
94
162
  export function meta(name:string,value:string) : ClassOrFieldDecoratorDef
95
163
  export function priority(value:string) : ClassOrFieldDecoratorDef
96
-
164
+ export function description(description:string) : ClassOrFieldDecoratorDef
165
+
97
166
  // Enum decorators
98
167
  export function flags() : ClassDecoratorDef
99
168
  export function enumMember(opt:{ value:string }) : ClassFieldDecoratorDef
100
-
169
+
101
170
  export function validate(validator:string) : ClassFieldDecoratorDef
102
171
  export function validateNull() : ClassFieldDecoratorDef
103
172
  export function validateEmpty() : ClassFieldDecoratorDef
@@ -119,10 +188,10 @@ declare global {
119
188
  export function validateNotEqualExpression(value:string|number|boolean) : ClassFieldDecoratorDef
120
189
  export function validateInclusiveBetween(from:string|number,to:string|number) : ClassFieldDecoratorDef
121
190
  export function validateExclusiveBetween(from:string|number,to:string|number) : ClassFieldDecoratorDef
122
-
191
+
123
192
  export function allowReset() : ClassFieldDecoratorDef
124
193
  export function denyReset() : ClassFieldDecoratorDef
125
-
194
+
126
195
  export function primaryKey() : ClassFieldDecoratorDef
127
196
  export function autoId() : ClassFieldDecoratorDef
128
197
  export function autoIncrement() : ClassFieldDecoratorDef
@@ -141,7 +210,6 @@ declare global {
141
210
  export function customUpdate(sql:string) : ClassFieldDecoratorDef
142
211
  export function decimalLength(precision:number, scale?:number) : ClassFieldDecoratorDef
143
212
  export function Default(value:string|number|boolean) : ClassFieldDecoratorDef
144
- export function description(description:string) : ClassFieldDecoratorDef
145
213
  export function enumAsInt() : ClassFieldDecoratorDef
146
214
  export function excludeMetadata() : ClassFieldDecoratorDef
147
215
  export function excludeFromDescription() : ClassFieldDecoratorDef
@@ -159,61 +227,58 @@ declare global {
159
227
  export function returnOnInsert() : ClassFieldDecoratorDef
160
228
  export function rowVersion() : ClassFieldDecoratorDef
161
229
  export function unique() : ClassFieldDecoratorDef
162
-
230
+
163
231
  export enum ValueStyle { Single, Multiple, List, }
164
232
  export function queryDbField(opt?:{ term:QueryTerm, operand?:string, template?:string, field?:string, valueFormat?:string, valueStyle?:ValueStyle, valueArity?:number }) : ClassFieldDecoratorDef
165
233
  export function queryDataField(opt?:{ term:QueryTerm, condition?:string, field?:string }) : ClassFieldDecoratorDef
166
-
234
+
167
235
  export enum AutoUpdateStyle { Always, NonDefaults }
168
236
  export function autoUpdate(style:AutoUpdateStyle) : ClassFieldDecoratorDef
169
- export function autoDefault(opt:ScriptValueOptions) : ClassFieldDecoratorDef
170
- export function autoMap(to:string) : ClassFieldDecoratorDef
237
+ export function autoDefault(opt:ScriptValueOptions) : ClassOrFieldDecoratorDef
238
+ export function autoMap(to:string) : ClassOrFieldDecoratorDef
171
239
  export function autoIgnore() : ClassFieldDecoratorDef
172
- export function autoApply(name:string, args?:string[]) : ClassFieldDecoratorDef
173
-
240
+
174
241
  export function apiMember(opt?:{ name?:string, verb?:string, parameterType?:string, description?:string, dataType?:string,
175
242
  format?:string, isRequired?:boolean, isOptional?:boolean, allowMultiple?:boolean, route?:string, excludeInSchema?:boolean
176
243
  }) : ClassFieldDecoratorDef
177
244
  export function apiAllowableValues(name:string, opt?:{ type?:"RANGE"|"LIST", min?:number, max?:number, values?:string[] }) : ClassFieldDecoratorDef
178
-
245
+
179
246
  export function dataMember(opt?:{ name?:string, order?:number, isRequired?:boolean }) : ClassFieldDecoratorDef
180
247
  export function input(opt?:InputAttrOptions) : ClassFieldDecoratorDef
181
248
  export function fieldCss(opt?:{ field?:string, input?:string, label?:string, }) : ClassFieldDecoratorDef
182
- export function explorerCss(opt?:{ form?:string, fieldset?:string, field?:string, }) : ClassFieldDecoratorDef
183
- export function locodeCss(opt?:{ form?:string, fieldset?:string, field?:string, }) : ClassFieldDecoratorDef
184
249
  export function uploadTo(location:string) : ClassFieldDecoratorDef
185
250
  export function ref(opt?:{ modelType?:TypeOf, model?:string, refId?:string, refLabel?:string, selfId?:string, queryType?:TypeOf, none?:boolean, }) : ClassFieldDecoratorDef
186
251
  export type FormatMethods = "currency"|"bytes"|"icon"|"iconRounded"|"attachment"|"link"|"linkMailTo"|"linkTel"|"enumFlags"|"hidden"
187
252
  export function format(method:FormatMethods, opt?:{ options?:string, locale?:string }) : ClassFieldDecoratorDef
188
-
253
+
189
254
  export enum IntlFormat { Number, DateTime, RelativeTime }
190
255
  export enum NumberStyle { Undefined=0, Decimal, Currency, Percent, Unit, }
191
256
  export enum DateStyle { Undefined=0, Full, Long, Medium, Short, }
192
257
  export enum TimeStyle { Undefined=0, Full, Long, Medium, Short, }
193
258
  export enum Numeric { Undefined=0, Always, Auto, }
194
-
259
+
195
260
  export enum DatePart { Undefined=0, Numeric, Digits2, }
196
261
  export enum DateMonth { Undefined=0, Numeric, Digits2, Narrow, Short, Long, }
197
262
  export enum DateText { Undefined=0, Narrow, Short, Long }
198
-
263
+
199
264
  export enum CurrencyDisplay { Undefined=0, Symbol, NarrowSymbol, Code, Name, }
200
265
  export enum CurrencySign { Undefined=0, Accounting, Standard, }
201
266
  export enum SignDisplay { Undefined=0, Always, Auto, ExceptZero, Negative, Never, }
202
267
  export enum RoundingMode { Undefined=0, Ceil, Floor, Expand, Trunc, HalfCeil, HalfFloor, HalfExpand, HalfTrunc, HalfEven, }
203
-
268
+
204
269
  export enum UnitDisplay { Undefined=0, Long, Short, Narrow }
205
270
  export enum Notation { Undefined=0, Standard, Scientific, Engineering, Compact, }
206
-
271
+
207
272
  export type IntlOptions = { locale?:string, options?:string, number?:NumberStyle, date?:DateStyle, time?:TimeStyle, numeric?:Numeric,
208
273
  currency?:string, currencyDisplay?:CurrencyDisplay, currencySign?:CurrencySign, signDisplay?:SignDisplay, roundingMode?:RoundingMode,
209
274
  unit?:string, unitDisplay?:UnitDisplay, notation?:Notation,
210
- minimumIntegerDigits?:number, minimumFractionDigits?:number, maximumFractionDigits?:number, minimumSignificantDigits?:number, maximumSignificantDigits?:number, fractionalSecondDigits?:number,
211
- weekday?:DateText, era?:DateText, year?:DatePart, month?:DateMonth, day?:DatePart, hour?:DatePart, minute?:DatePart, second?:DatePart,
275
+ minimumIntegerDigits?:number, minimumFractionDigits?:number, maximumFractionDigits?:number, minimumSignificantDigits?:number, maximumSignificantDigits?:number, fractionalSecondDigits?:number,
276
+ weekday?:DateText, era?:DateText, year?:DatePart, month?:DateMonth, day?:DatePart, hour?:DatePart, minute?:DatePart, second?:DatePart,
212
277
  timeZoneName?:DateText, timeZone?:string, hour12?:boolean
213
278
  }
214
-
279
+
215
280
  export function intl(type:IntlFormat, opt?:IntlOptions) : ClassFieldDecoratorDef
216
- export function intlNumber(number?:NumberStyle) : ClassFieldDecoratorDef
281
+ export function intlNumber(number?:NumberStyle|IntlOptions, opt?:IntlOptions) : ClassFieldDecoratorDef
217
282
  export function intlDateTime(date?:DateStyle, time?:TimeStyle) : ClassFieldDecoratorDef
218
283
  export function intlRelativeTime(numeric?:Numeric) : ClassFieldDecoratorDef
219
284
 
@@ -238,15 +303,16 @@ declare global {
238
303
  queryData:typeof queryData
239
304
  autoFilter:typeof autoFilter
240
305
  autoPopulate:typeof autoPopulate
306
+ autoApply:typeof autoApply
241
307
 
242
308
  route:typeof route
243
309
  field:typeof field
244
310
  tag:typeof tag
245
311
  notes:typeof notes
246
-
312
+
247
313
  // Type and Attrs
248
314
  dataContract:typeof dataContract
249
-
315
+
250
316
  // DataModelAttrs
251
317
  schema:typeof schema
252
318
  compositeKey:typeof compositeKey
@@ -257,12 +323,14 @@ declare global {
257
323
 
258
324
  namedConnection:typeof namedConnection
259
325
  icon:typeof icon
326
+ locodeCss: typeof locodeCss
327
+ explorerCss: typeof explorerCss
260
328
 
261
329
  // Class or Field Attrs
262
330
  alias:typeof alias
263
331
  meta:typeof meta // Type
264
332
  flags:typeof flags // Enum
265
-
333
+
266
334
  // RequestPropAttrs
267
335
  validate:typeof validate
268
336
  validateNull:typeof validateNull
@@ -294,7 +362,6 @@ declare global {
294
362
  autoDefault:typeof autoDefault
295
363
  autoMap:typeof autoMap
296
364
  autoIgnore:typeof autoIgnore
297
- autoApply:typeof autoApply
298
365
 
299
366
  apiMember:typeof apiMember
300
367
  apiAllowableValues:typeof apiAllowableValues
@@ -304,11 +371,12 @@ declare global {
304
371
  uploadTo:typeof uploadTo
305
372
 
306
373
  enumMember:typeof enumMember
307
-
374
+
308
375
  // DataModelPropAttrs
309
376
  // alias:typeof alias
310
377
  // meta:typeof meta
311
378
  priority:typeof priority
379
+ description:typeof description
312
380
 
313
381
  primaryKey:typeof primaryKey
314
382
  autoId:typeof autoId
@@ -328,7 +396,6 @@ declare global {
328
396
  customUpdate:typeof customUpdate
329
397
  decimalLength:typeof decimalLength
330
398
  Default:typeof Default
331
- description:typeof description
332
399
  enumAsInt:typeof enumAsInt
333
400
  excludeMetadata:typeof excludeMetadata
334
401
  excludeFromDescription:typeof excludeFromDescription
@@ -352,7 +419,7 @@ declare global {
352
419
  intlNumber:typeof intlNumber
353
420
  intlDateTime:typeof intlDateTime
354
421
  intlRelativeTime:typeof intlRelativeTime
355
- }
422
+ }
356
423
  export const Read : All
357
424
  export const Write : All
358
425
  export const Create : All
package/dist/cs-apis.js CHANGED
@@ -22,42 +22,49 @@ export class CSharpApiGenerator extends CSharpGenerator {
22
22
  : `IReturnVoid`);
23
23
  }
24
24
  }
25
- if (op.tags?.length) {
25
+ const attrs = cls.attributes ?? [];
26
+ const hasTypeAttr = (name) => attrs.some(x => x.name === name);
27
+ if (op.tags?.length && !attrs.some(x => x.name === 'Tag')) {
26
28
  for (const tag of op.tags) {
27
- sb.push(`[Tag("${tag}")]`);
29
+ attrs.push({ name: 'Tag', constructorArgs: [{ name: 'tag', type: 'string', value: tag }] });
28
30
  }
29
31
  }
30
32
  if (op.requiredRoles?.length) {
31
33
  const adminRole = op.requiredRoles.includes('Admin');
32
- if (adminRole && !this.typeHasAttr(op.request, 'ValidateIsAdmin')) {
33
- sb.push(`[ValidateIsAdmin]`);
34
+ if (adminRole && !hasTypeAttr('ValidateIsAdmin')) {
35
+ attrs.push({ name: 'ValidateIsAdmin' });
34
36
  }
35
37
  const roles = op.requiredRoles.filter(r => r !== 'Admin');
36
- if (roles.length && !this.typeHasAttr(op.request, 'ValidateHasRole')) {
37
- sb.push(`[ValidateHasRole("${roles[0]}")]`);
38
+ if (roles.length && !hasTypeAttr('ValidateHasRole')) {
39
+ attrs.push({ name: 'ValidateHasRole', constructorArgs: [{ name: 'role', type: 'string', value: roles[0] }] });
38
40
  }
39
41
  }
40
- else if (op.requiresAuth && !this.typeHasAttr(op.request, 'ValidateIsAuthenticated')) {
41
- sb.push(`[ValidateIsAuthenticated]`);
42
+ else if (op.requiresAuth && !(hasTypeAttr('ValidateIsAuthenticated') || hasTypeAttr('ValidateIsAdmin') || hasTypeAttr('ValidateHasRole'))) {
43
+ attrs.push({ name: 'ValidateIsAuthenticated' });
42
44
  }
43
- if (cls.description && !this.typeHasAttr(op.request, 'Api')) {
44
- sb.push(`[Api("${cls.description}")]`);
45
+ if (cls.description && !hasTypeAttr('Api')) {
46
+ attrs.push({ name: 'Api', constructorArgs: [{ name: 'description', type: 'string', value: cls.description }] });
45
47
  }
46
- for (const attr of cls.attributes ?? []) {
47
- sb.push(this.toAttribtue(attr));
48
- }
49
- if (op.routes?.length) {
48
+ if (op.routes?.length && !attrs.some(x => x.name === 'Route')) {
50
49
  for (const route of op.routes) {
51
- sb.push(`[Route("${route.path}", "${route.verbs ?? "POST"}")]`);
50
+ attrs.push({ name: 'Route', constructorArgs: [
51
+ { name: 'path', type: 'string', value: route.path },
52
+ { name: 'verbs', type: 'string', value: route.verbs ?? "POST" }
53
+ ] });
52
54
  }
53
55
  }
56
+ for (const attr of this.sortAttributes(attrs)) {
57
+ sb.push(this.toAttribtue(attr));
58
+ }
54
59
  sb.push(clsDef);
55
60
  sb.push('{');
56
61
  for (const prop of cls.properties) {
62
+ const hasPropAttr = (name) => prop.attributes?.some(x => x.name === name);
63
+ const attrs = prop.attributes ?? [];
57
64
  this.addNamespace(prop.namespace);
58
- if (prop.description && !this.propHasAttr(prop, 'ApiMember')) {
65
+ if (prop.description && !hasPropAttr('ApiMember')) {
59
66
  if (!prop.description.includes('\n')) {
60
- sb.push(` [ApiMember(Description="${prop.description.replace(/"/g, '\\"')}")]`);
67
+ attrs.push({ name: 'ApiMember', args: [{ name: 'Description', type: 'string', value: prop.description.replace(/"/g, '\\"') }] });
61
68
  }
62
69
  else {
63
70
  sb.push(` [ApiMember(Description=\n` +
@@ -66,7 +73,7 @@ export class CSharpApiGenerator extends CSharpGenerator {
66
73
  ` """)]`);
67
74
  }
68
75
  }
69
- for (const attr of prop.attributes ?? []) {
76
+ for (const attr of this.sortAttributes(attrs)) {
70
77
  const def = this.toAttribtue(attr);
71
78
  sb.push(` ${def}`);
72
79
  }
package/dist/cs-ast.js CHANGED
@@ -1,5 +1,5 @@
1
- import { getGroupName, leftPart, plural, rightPart, splitCase, toPascalCase } from "./utils.js";
2
- import { Icons } from "./icons.js";
1
+ import { getGroupName, lastLeftPart, leftPart, plural, rightPart, splitCase, toPascalCase } from "./utils.js";
2
+ import { getIcon } from "./icons.js";
3
3
  const sys = (name, genericArgs) => ({ name, namespace: "System", genericArgs });
4
4
  const sysObj = sys("object");
5
5
  const sysDictObj = { name: "Dictionary", genericArgs: ["string", "object"], namespace: "System.Collections.Generic" };
@@ -38,9 +38,6 @@ export class CSharpAst {
38
38
  decimalTypeProps = [
39
39
  "price", "cost", "amount", "total", "salary", "balance", "rate", "discount", "tax", "fee"
40
40
  ];
41
- currencyTypeProps = [
42
- "price", "cost", "total", "salary", "balance", "tax", "fee"
43
- ];
44
41
  valueTypes = [
45
42
  "int", "long", "short", "ulong", "ushort", "sbyte", "uint", "char", "byte", "float", "double", "decimal", "bool",
46
43
  "Int16", "Int32", "Int64", "UInt16", "UInt32", "UInt64", "SByte", "Byte", "Single", "Double", "Decimal", "Boolean",
@@ -75,6 +72,7 @@ export class CSharpAst {
75
72
  'field',
76
73
  'tag',
77
74
  'notes',
75
+ 'description',
78
76
  'meta',
79
77
  'dataContract',
80
78
  ].map(x => x.toLowerCase());
@@ -90,6 +88,8 @@ export class CSharpAst {
90
88
  'icon',
91
89
  'meta',
92
90
  'dataContract',
91
+ 'notes',
92
+ 'description',
93
93
  ].map(x => x.toLowerCase());
94
94
  requestPropAttrs = [
95
95
  'validate',
@@ -179,6 +179,11 @@ export class CSharpAst {
179
179
  'intlDateTime',
180
180
  'intlRelativeTime',
181
181
  ].map(x => x.toLowerCase());
182
+ // Only generate these attributes when it's API specific, e.g. Read.notes("...")
183
+ targetOnlyAttrs = [
184
+ 'notes',
185
+ 'description',
186
+ ].map(x => x.toLowerCase());
182
187
  // Ignore properties with these attributes on APIs
183
188
  ignoreCreateProps = [
184
189
  'autoIncrement',
@@ -312,14 +317,6 @@ export class CSharpAst {
312
317
  if (!prop.isValueType && !prop.type.endsWith('?')) {
313
318
  prop.isRequired = true;
314
319
  }
315
- if (this.currencyTypeProps.some(x => prop.name.toLowerCase().includes(x))) {
316
- if (!prop.attributes)
317
- prop.attributes = [];
318
- prop.attributes.push({
319
- name: "IntlNumber",
320
- args: [{ name: "Currency", type: "constant", value: "NumberCurrency.USD" }]
321
- });
322
- }
323
320
  if (p.annotations?.length) {
324
321
  prop.attributes = p.annotations.map(x => this.csharpAttribute(x));
325
322
  }
@@ -332,6 +329,9 @@ export class CSharpAst {
332
329
  if (cls.extends) {
333
330
  type.inherits = { name: this.toCsName(cls.extends) };
334
331
  }
332
+ if (cls.implements?.length) {
333
+ type.implements = cls.implements.filter(x => !x.startsWith("IReturn")).map(x => this.csharpType(x));
334
+ }
335
335
  if (cls.annotations?.length) {
336
336
  type.attributes = cls.annotations.map(x => this.csharpAttribute(x));
337
337
  }
@@ -348,8 +348,46 @@ export class CSharpAst {
348
348
  this.addMetadataType(refType);
349
349
  }
350
350
  });
351
- if (!this.result.types.find(x => x.name === cls.name && x.namespace === 'MyApp')) {
352
- this.result.types.push(type);
351
+ if (isDataModel(type) || type.isEnum) {
352
+ if (!this.result.types.find(x => x.name === cls.name && x.namespace === 'MyApp')) {
353
+ this.result.types.push(type);
354
+ }
355
+ }
356
+ else {
357
+ if (!this.result.operations.find(x => x.request.name === cls.name)) {
358
+ let method = "POST";
359
+ if (cls.extends?.startsWith('Query')) {
360
+ method = "GET";
361
+ }
362
+ let impls = cls.implements;
363
+ if (impls?.length) {
364
+ if (impls.includes('ICreate')) {
365
+ method = "POST";
366
+ }
367
+ else if (impls.includes('IUpdate')) {
368
+ method = "PUT";
369
+ }
370
+ else if (impls.includes('IPatch')) {
371
+ method = "PATCH";
372
+ }
373
+ else if (impls.includes('IDelete')) {
374
+ method = "DELETE";
375
+ }
376
+ }
377
+ const op = {
378
+ request: type,
379
+ actions: ["ANY"],
380
+ method,
381
+ };
382
+ const iReturn = impls?.find(x => x.startsWith('IReturn<'));
383
+ if (iReturn) {
384
+ op.returnType = this.csharpType(lastLeftPart(rightPart(iReturn, '<'), '>'));
385
+ }
386
+ if (impls?.includes('IReturnVoid')) {
387
+ op.returnsVoid = true;
388
+ }
389
+ this.result.operations.push(op);
390
+ }
353
391
  }
354
392
  return type;
355
393
  }
@@ -413,6 +451,7 @@ export class CSharpAst {
413
451
  ? this.ignoreDeleteValidators
414
452
  : []
415
453
  : [];
454
+ const targetOnlyAttrs = this.targetOnlyAttrs;
416
455
  function shouldInclude(attr, dtoType) {
417
456
  if (!validAttrs.includes(attr.name.toLowerCase()))
418
457
  return false;
@@ -436,6 +475,9 @@ export class CSharpAst {
436
475
  const nameLower = attr.name.toLowerCase();
437
476
  if (isRequest) {
438
477
  if (attrType === "Type") {
478
+ if (targetOnlyAttrs.includes(nameLower)) {
479
+ return false;
480
+ }
439
481
  return requestAttrs.includes(nameLower);
440
482
  }
441
483
  else if (attrType === "Prop") {
@@ -467,12 +509,15 @@ export class CSharpAst {
467
509
  const groupName = getGroupName(this.result);
468
510
  const friendlyGroupName = splitCase(groupName);
469
511
  for (const type of this.classes) {
512
+ if (!isDataModel(type))
513
+ continue;
470
514
  const hasPk = type.properties?.some(x => x.isPrimaryKey);
471
515
  if (!hasPk)
472
516
  continue;
473
517
  const pluralizedType = plural(type.name);
474
518
  const queryName = `Query${pluralizedType}`;
475
- let queryApi = this.result.operations.find(x => x.request.name === queryName);
519
+ let queryApi = this.result.operations.find(x => x.request.name === queryName
520
+ || (x.request.inherits?.name.startsWith('Query') && x.request.inherits?.genericArgs?.some(a => a === type.name)));
476
521
  const pk = type.properties?.find(x => x.isPrimaryKey);
477
522
  const dataModel = { name: type.name, namespace: type.name };
478
523
  const isAuditBase = type.inherits?.name === 'AuditBase';
@@ -545,7 +590,8 @@ export class CSharpAst {
545
590
  this.result.operations.push(queryApi);
546
591
  }
547
592
  let createName = `Create${type.name}`;
548
- let createApi = this.result.operations.find(x => x.request.name === createName);
593
+ let createApi = this.result.operations.find(x => x.request.name === createName
594
+ || (x.request.implements?.some(i => i.name.startsWith("ICreate") && x.dataModel == dataModel)));
549
595
  if (!createApi) {
550
596
  createApi = {
551
597
  method: "POST",
@@ -619,7 +665,9 @@ export class CSharpAst {
619
665
  this.result.operations.push(createApi);
620
666
  }
621
667
  let updateName = `Update${type.name}`;
622
- let updateApi = this.result.operations.find(x => x.request.name === updateName);
668
+ let updateApi = this.result.operations.find(x => x.request.name === updateName
669
+ || x.dataModel == dataModel && (x.request.implements?.some(i => i.name.startsWith("IPatch")) ||
670
+ x.request.implements?.some(i => i.name.startsWith("IUpdate"))));
623
671
  if (!updateApi) {
624
672
  updateApi = {
625
673
  method: "PATCH",
@@ -672,7 +720,8 @@ export class CSharpAst {
672
720
  this.result.operations.push(updateApi);
673
721
  }
674
722
  let deleteName = `Delete${type.name}`;
675
- let deleteApi = this.result.operations.find(x => x.request.name === deleteName);
723
+ let deleteApi = this.result.operations.find(x => x.request.name === deleteName
724
+ || (x.request.implements?.some(i => i.name.startsWith("IDelete") && x.dataModel == dataModel)));
676
725
  if (!deleteApi) {
677
726
  deleteApi = {
678
727
  method: "DELETE",
@@ -721,6 +770,8 @@ export class CSharpAst {
721
770
  }
722
771
  filterModelAttributes() {
723
772
  for (const type of this.classes) {
773
+ if (!isDataModel(type))
774
+ continue;
724
775
  if (type.attributes?.length) {
725
776
  type.attributes = this.attrsFor("Model", "Type", type.attributes);
726
777
  }
@@ -822,9 +873,6 @@ export function replaceReference(gen, fromType, toType) {
822
873
  }
823
874
  }
824
875
  }
825
- export function replaceServiceReferences(gen) {
826
- replaceReferences(gen, ['Service']);
827
- }
828
876
  export function replaceReferences(gen, references) {
829
877
  // The most important types are the ones with the most references
830
878
  const refCount = (t) => t.properties?.filter(p => gen.result.types.find(x => x.name === p.type && p.namespace === 'MyApp')).length || 0;
@@ -1000,7 +1048,7 @@ export function addAutoIncrementAttrs(gen) {
1000
1048
  // Add Icon for BuiltIn UIs and AutoQueryGrid to known type names
1001
1049
  export function addIconsToKnownTypes(gen) {
1002
1050
  for (const type of gen.typesWithPrimaryKeys) {
1003
- const icon = Icons[type.name];
1051
+ const icon = getIcon(type.name);
1004
1052
  if (icon) {
1005
1053
  if (!type.attributes)
1006
1054
  type.attributes = [];
@@ -1059,3 +1107,8 @@ export function replaceUserReferencesWithAuditTables(gen) {
1059
1107
  // Remove User Table
1060
1108
  gen.result.types = gen.result.types.filter(x => x.name !== 'User');
1061
1109
  }
1110
+ export function isDataModel(type) {
1111
+ const apiInterfacePrefixes = ['IReturn', 'IQuery', 'ICreate', 'IUpdate', 'IPatch', 'IDelete', 'IGet', 'IPost', 'IPut'];
1112
+ return (!type.inherits || !type.inherits.name.startsWith("Query"))
1113
+ && (!type.implements || !type.implements.some(x => apiInterfacePrefixes.some(prefix => x.name.startsWith(prefix))));
1114
+ }