@voxgig/sdkgen 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/voxgig-sdkgen +12 -4
- package/dist/action/action.d.ts +4 -0
- package/dist/action/action.js +35 -0
- package/dist/action/action.js.map +1 -0
- package/dist/action/feature.d.ts +4 -2
- package/dist/action/feature.js +57 -38
- package/dist/action/feature.js.map +1 -1
- package/dist/action/target.d.ts +4 -2
- package/dist/action/target.js +136 -45
- package/dist/action/target.js.map +1 -1
- package/dist/cmp/Entity.js +5 -0
- package/dist/cmp/Entity.js.map +1 -1
- package/dist/cmp/Feature.js +5 -0
- package/dist/cmp/Feature.js.map +1 -1
- package/dist/cmp/Main.js +4 -1
- package/dist/cmp/Main.js.map +1 -1
- package/dist/cmp/Top.d.ts +2 -0
- package/dist/cmp/Top.js +23 -0
- package/dist/cmp/Top.js.map +1 -0
- package/dist/sdkgen.d.ts +10 -3
- package/dist/sdkgen.js +53 -8
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utility.d.ts +3 -3
- package/dist/utility.js +7 -8
- package/dist/utility.js.map +1 -1
- package/package.json +6 -10
- package/project/.sdk/model/feature/README.md +2 -0
- package/project/.sdk/model/feature/log.jsonic +7 -4
- package/project/.sdk/model/feature/test.jsonic +26 -0
- package/project/.sdk/model/target/ts.jsonic +1 -0
- package/project/.sdk/src/cmp/ts/Config_ts.ts +7 -2
- package/project/.sdk/src/cmp/ts/EntityOperation_ts.ts +67 -0
- package/project/.sdk/src/cmp/ts/EntityTest_ts.ts +180 -0
- package/project/.sdk/src/cmp/ts/Entity_ts.ts +41 -66
- package/project/.sdk/src/cmp/ts/MainEntity_ts.ts +22 -0
- package/project/.sdk/src/cmp/ts/Main_ts.ts +52 -53
- package/project/.sdk/src/cmp/ts/Package_ts.ts +12 -7
- package/project/.sdk/src/cmp/ts/ReadmeInstall_ts.ts +19 -0
- package/project/.sdk/src/cmp/ts/ReadmeQuick_ts.ts +24 -0
- package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +13 -0
- package/project/.sdk/src/cmp/ts/TestMain_ts.ts +19 -0
- package/project/.sdk/src/cmp/ts/Test_ts.ts +20 -0
- package/project/.sdk/src/cmp/ts/fragment/Config.fragment.ts +8 -1
- package/project/.sdk/src/cmp/ts/fragment/Entity.fragment.ts +164 -0
- package/project/.sdk/src/cmp/ts/fragment/Entity.test.fragment.ts +37 -0
- package/project/.sdk/src/cmp/ts/fragment/EntityCreateOp.fragment.ts +91 -0
- package/project/.sdk/src/cmp/ts/fragment/EntityListOp.fragment.ts +92 -0
- package/project/.sdk/src/cmp/ts/fragment/EntityLoadOp.fragment.ts +96 -0
- package/project/.sdk/src/cmp/ts/fragment/EntityRemoveOp.fragment.ts +96 -0
- package/project/.sdk/src/cmp/ts/fragment/EntityUpdateOp.fragment.ts +95 -0
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.ts +107 -0
- package/project/.sdk/src/cmp/ts/utility_ts.ts +10 -0
- package/project/.sdk/tm/ts/src/feature/base/BaseFeature.ts +43 -0
- package/project/.sdk/tm/ts/src/feature/log/LogFeature.ts +109 -0
- package/project/.sdk/tm/ts/src/feature/test/TestFeature.ts +159 -0
- package/project/.sdk/tm/ts/src/tsconfig.json +1 -1
- package/project/.sdk/tm/ts/src/types.ts +114 -0
- package/project/.sdk/tm/ts/src/utility/AddfeatureUtility.ts +47 -0
- package/project/.sdk/tm/ts/src/utility/AuthUtility.ts +42 -0
- package/project/.sdk/tm/ts/src/utility/BodyUtility.ts +29 -0
- package/project/.sdk/tm/ts/src/utility/CleanUtility.ts +50 -0
- package/project/.sdk/tm/ts/src/utility/ContextUtility.ts +67 -0
- package/project/.sdk/tm/ts/src/utility/DoneUtility.ts +28 -0
- package/project/.sdk/tm/ts/src/utility/ErrorUtility.ts +59 -0
- package/project/.sdk/tm/ts/src/utility/FeaturehookUtility.ts +26 -0
- package/project/.sdk/tm/ts/src/utility/FetcherUtility.ts +17 -0
- package/project/.sdk/tm/ts/src/utility/FindparamUtility.ts +54 -0
- package/project/.sdk/tm/ts/src/utility/FullurlUtility.ts +46 -0
- package/project/.sdk/tm/ts/src/utility/HeadersUtility.ts +24 -0
- package/project/.sdk/tm/ts/src/utility/InitfeatureUtility.ts +13 -0
- package/project/.sdk/tm/ts/src/utility/JoinurlUtility.ts +15 -0
- package/project/.sdk/tm/ts/src/utility/MethodUtility.ts +25 -0
- package/project/.sdk/tm/ts/src/utility/OperatorUtility.ts +90 -0
- package/project/.sdk/tm/ts/src/utility/OptionsUtility.ts +72 -0
- package/project/.sdk/tm/ts/src/utility/ParamsUtility.ts +37 -0
- package/project/.sdk/tm/ts/src/utility/QueryUtility.ts +27 -0
- package/project/.sdk/tm/ts/src/utility/ReqformUtility.ts +33 -0
- package/project/.sdk/tm/ts/src/utility/RequestUtility.ts +66 -0
- package/project/.sdk/tm/ts/src/utility/ResbasicUtility.ts +34 -0
- package/project/.sdk/tm/ts/src/utility/ResbodyUtility.ts +19 -0
- package/project/.sdk/tm/ts/src/utility/ResformUtility.ts +36 -0
- package/project/.sdk/tm/ts/src/utility/ResheadersUtility.ts +23 -0
- package/project/.sdk/tm/ts/src/utility/ResponseUtility.ts +30 -0
- package/project/.sdk/tm/ts/src/utility/ResultUtility.ts +36 -0
- package/project/.sdk/tm/ts/src/utility/SpecUtility.ts +61 -0
- package/project/.sdk/tm/ts/src/utility/StructUtility.ts +2499 -0
- package/project/.sdk/tm/ts/src/utility/Utility.ts +88 -0
- package/project/.sdk/tm/ts/test/exists.test.ts +17 -0
- package/project/.sdk/tm/ts/test/runner.ts +402 -0
- package/project/.sdk/tm/ts/test/tsconfig.json +1 -1
- package/project/.sdk/tm/ts/test/utility/Custom.test.ts +62 -0
- package/project/.sdk/tm/ts/test/utility/PrimaryUtility.test.ts +244 -0
- package/project/.sdk/tm/ts/test/utility/StructUtility.test.ts +678 -0
- package/project/.sdk/tm/ts/test/utility/index.ts +9 -0
- package/project/.sdk/tm/ts/test/utility.ts +86 -0
- package/src/action/action.ts +54 -0
- package/src/action/feature.ts +83 -47
- package/src/action/target.ts +173 -53
- package/src/cmp/Entity.ts +6 -0
- package/src/cmp/Feature.ts +6 -3
- package/src/cmp/Main.ts +4 -1
- package/src/sdkgen.ts +86 -11
- package/src/types.ts +33 -0
- package/src/utility.ts +5 -3
- package/project/.sdk/model/feature/limit.jsonic +0 -12
- package/project/.sdk/model/feature/page.jsonic +0 -9
- package/project/.sdk/model/feature/telemetry.jsonic +0 -10
- package/project/.sdk/src/cmp/ts/fragment/Entity.fragment.js +0 -79
- package/project/.sdk/src/cmp/ts/fragment/EntityCreateOp.fragment.js +0 -61
- package/project/.sdk/src/cmp/ts/fragment/EntityListOp.fragment.js +0 -57
- package/project/.sdk/src/cmp/ts/fragment/EntityLoadOp.fragment.js +0 -61
- package/project/.sdk/src/cmp/ts/fragment/EntityRemoveOp.fragment.js +0 -61
- package/project/.sdk/src/cmp/ts/fragment/EntityUpdateOp.fragment.js +0 -61
- package/project/.sdk/src/cmp/ts/fragment/Main.fragment.js +0 -67
- package/project/.sdk/tm/ts/test/README.md~ +0 -2
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utility functions for unit tests
|
|
3
|
+
*
|
|
4
|
+
* This module provides common helper functions used across unit tests
|
|
5
|
+
* for creating test data, transformations, validations, and environment overrides.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Creates a new step data structure within the data model
|
|
9
|
+
function makeStepData(dm: Record<string, any>, stepname: string): Record<string, any> {
|
|
10
|
+
dm.s[stepname] = {
|
|
11
|
+
entity: undefined,
|
|
12
|
+
match: undefined,
|
|
13
|
+
reqdata: undefined,
|
|
14
|
+
resdata: undefined,
|
|
15
|
+
}
|
|
16
|
+
return dm.s[stepname]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
// Transforms and creates a match object using the provided transform function
|
|
21
|
+
function makeMatch(
|
|
22
|
+
dm: Record<string, any>,
|
|
23
|
+
transform: Function,
|
|
24
|
+
match: any
|
|
25
|
+
): Record<string, any> {
|
|
26
|
+
return transform({}, match, { meta: { dm } })
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
// Transforms and creates request data using the provided transform function
|
|
31
|
+
function makeReqdata(
|
|
32
|
+
dm: Record<string, any>,
|
|
33
|
+
transform: Function,
|
|
34
|
+
data: any
|
|
35
|
+
): Record<string, any> {
|
|
36
|
+
return transform({}, data, { meta: { dm } })
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
// Validates data against validation rules and returns the result
|
|
41
|
+
function makeValid(
|
|
42
|
+
dm: Record<string, any>,
|
|
43
|
+
validate: Function,
|
|
44
|
+
data: any,
|
|
45
|
+
valid: any
|
|
46
|
+
): Record<string, any> {
|
|
47
|
+
valid["`$OPEN`"] = true
|
|
48
|
+
return validate(data, valid, { meta: { '`$EXISTS`': true, dm } })
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
// Creates a control object for test explanations when enabled
|
|
53
|
+
function makeCtrl(explain: boolean) {
|
|
54
|
+
return explain ? { explain: {} } : undefined
|
|
55
|
+
}
|
|
56
|
+
// CLAUDE: add a full stop to each function comment
|
|
57
|
+
|
|
58
|
+
// Overrides configuration values with environment variables if available
|
|
59
|
+
function envOverride(m: Record<string, any>) {
|
|
60
|
+
if (
|
|
61
|
+
'TRUE' === process.env.PROJECTNAME_TEST_LIVE ||
|
|
62
|
+
'TRUE' === process.env.PROJECTNAME_TEST_OVERRIDE
|
|
63
|
+
) {
|
|
64
|
+
Object.entries(m).map(n => {
|
|
65
|
+
let envval = process.env[n[0]]
|
|
66
|
+
if (null != envval) {
|
|
67
|
+
envval = envval.trim()
|
|
68
|
+
m[n[0]] = envval.startsWith('{') ? JSON.parse(envval) : envval
|
|
69
|
+
}
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
m.PROJECTNAME_TEST_EXPLAIN = process.env.PROJECTNAME_TEST_EXPLAIN || m.PROJECTNAME_TEST_EXPLAIN
|
|
74
|
+
|
|
75
|
+
return m
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
export {
|
|
80
|
+
makeStepData,
|
|
81
|
+
makeMatch,
|
|
82
|
+
makeReqdata,
|
|
83
|
+
makeValid,
|
|
84
|
+
makeCtrl,
|
|
85
|
+
envOverride
|
|
86
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
import Path from 'node:path'
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
Content,
|
|
6
|
+
cmp,
|
|
7
|
+
} from 'jostraca'
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
ActionContext,
|
|
12
|
+
} from '../types'
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
const UpdateIndex = cmp(function UpdateIndex(props: any) {
|
|
16
|
+
const names = props.names
|
|
17
|
+
|
|
18
|
+
let oldcontent = props.content
|
|
19
|
+
let newcontent = oldcontent
|
|
20
|
+
|
|
21
|
+
names.map((n: string) => {
|
|
22
|
+
if (!oldcontent.includes(`@"${n}.jsonic"`)) {
|
|
23
|
+
newcontent += `\n@"${n}.jsonic"`
|
|
24
|
+
}
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
Content(newcontent)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
function loadContent(actx: ActionContext, which: string | string[]) {
|
|
32
|
+
which = Array.isArray(which) ? which : [which]
|
|
33
|
+
|
|
34
|
+
const content: any = {}
|
|
35
|
+
|
|
36
|
+
const fs = actx.fs()
|
|
37
|
+
const tree = actx.tree
|
|
38
|
+
const modelfolder = Path.dirname(tree.url)
|
|
39
|
+
|
|
40
|
+
which.map((w: string) => {
|
|
41
|
+
const indexfile = Path.join(modelfolder, w, w + '-index.jsonic')
|
|
42
|
+
const indexcontent = fs.readFileSync(indexfile, 'utf8')
|
|
43
|
+
content[`${w}_index`] = indexcontent
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
return content
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
UpdateIndex,
|
|
53
|
+
loadContent
|
|
54
|
+
}
|
package/src/action/feature.ts
CHANGED
|
@@ -1,19 +1,32 @@
|
|
|
1
1
|
|
|
2
|
+
import Path from 'node:path'
|
|
3
|
+
|
|
2
4
|
import {
|
|
3
5
|
Jostraca,
|
|
4
6
|
Project,
|
|
5
7
|
File,
|
|
6
8
|
Folder,
|
|
7
|
-
Content,
|
|
8
9
|
Copy,
|
|
9
10
|
cmp,
|
|
10
11
|
each,
|
|
11
12
|
} from 'jostraca'
|
|
12
13
|
|
|
14
|
+
import { showChanges } from '@voxgig/util'
|
|
15
|
+
|
|
16
|
+
import type {
|
|
17
|
+
ActionContext,
|
|
18
|
+
ActionResult,
|
|
19
|
+
} from '../types'
|
|
13
20
|
|
|
14
21
|
import { SdkGenError } from '../utility'
|
|
15
22
|
|
|
16
23
|
|
|
24
|
+
import {
|
|
25
|
+
UpdateIndex,
|
|
26
|
+
loadContent,
|
|
27
|
+
} from './action'
|
|
28
|
+
|
|
29
|
+
|
|
17
30
|
const CMD_MAP: any = {
|
|
18
31
|
add: cmd_feature_add
|
|
19
32
|
}
|
|
@@ -21,7 +34,7 @@ const CMD_MAP: any = {
|
|
|
21
34
|
const BASE = 'node_modules/@voxgig/sdkgen'
|
|
22
35
|
|
|
23
36
|
|
|
24
|
-
async function action_feature(args:
|
|
37
|
+
async function action_feature(args: string[], actx: ActionContext): Promise<ActionResult> {
|
|
25
38
|
|
|
26
39
|
const cmdname = args[1]
|
|
27
40
|
|
|
@@ -31,91 +44,114 @@ async function action_feature(args: any[], ctx: any) {
|
|
|
31
44
|
throw new SdkGenError('Unknown feature cmd: ' + cmdname)
|
|
32
45
|
}
|
|
33
46
|
|
|
34
|
-
await cmd(args,
|
|
47
|
+
return await cmd(args, actx)
|
|
35
48
|
}
|
|
36
49
|
|
|
37
50
|
|
|
38
|
-
async function cmd_feature_add(args:
|
|
51
|
+
async function cmd_feature_add(args: string[], actx: ActionContext): Promise<ActionResult> {
|
|
52
|
+
|
|
53
|
+
const features_arg = args[2]
|
|
54
|
+
const features: string[] =
|
|
55
|
+
'string' === typeof features_arg ? features_arg.split(',') : features_arg
|
|
56
|
+
|
|
57
|
+
return feature_add(features, actx)
|
|
58
|
+
}
|
|
59
|
+
|
|
39
60
|
|
|
40
|
-
|
|
41
|
-
features = 'string' === typeof features ? features.split(',') : features
|
|
61
|
+
async function feature_add(features: string[], actx: ActionContext): Promise<ActionResult> {
|
|
42
62
|
|
|
43
63
|
const jostraca = Jostraca()
|
|
44
64
|
|
|
45
65
|
const opts = {
|
|
46
|
-
fs:
|
|
47
|
-
folder:
|
|
48
|
-
log:
|
|
49
|
-
meta: {
|
|
66
|
+
fs: actx.fs,
|
|
67
|
+
folder: actx.folder,
|
|
68
|
+
log: actx.log.child({ cmp: 'jostraca' }),
|
|
69
|
+
meta: {
|
|
70
|
+
// model: actx.model,
|
|
71
|
+
tree: actx.tree,
|
|
72
|
+
content: loadContent(actx, 'feature')
|
|
73
|
+
},
|
|
74
|
+
model: actx.model
|
|
50
75
|
}
|
|
51
76
|
|
|
52
|
-
|
|
77
|
+
opts.log.info({
|
|
78
|
+
point: 'feature-start',
|
|
79
|
+
note: (actx.opts.dryrun ? '** DRY RUN **' : '')
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
const jres = await jostraca.generate(opts, () => FeatureRoot({ features }))
|
|
83
|
+
|
|
84
|
+
showChanges(opts.log, 'feature-result', jres)
|
|
85
|
+
|
|
86
|
+
opts.log.info({
|
|
87
|
+
point: 'feature-end',
|
|
88
|
+
note: (actx.opts.dryrun ? '** DRY RUN **' : '')
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
jres
|
|
93
|
+
}
|
|
53
94
|
}
|
|
54
95
|
|
|
55
96
|
|
|
56
97
|
const FeatureRoot = cmp(function FeatureRoot(props: any) {
|
|
57
98
|
const { ctx$, features } = props
|
|
99
|
+
const { model, log } = ctx$
|
|
58
100
|
|
|
59
|
-
// TODO: model should be a top level ctx property
|
|
60
|
-
const model = ctx$.model = ctx$.meta.model
|
|
61
101
|
const target = model.main.sdk.target
|
|
62
102
|
|
|
63
103
|
Project({}, () => {
|
|
64
104
|
each(features, (n) => {
|
|
65
|
-
const
|
|
105
|
+
const fname = n.val$
|
|
66
106
|
// TODO: validate feature is a-z0-9-_. only
|
|
67
107
|
|
|
108
|
+
log.info({
|
|
109
|
+
point: 'feature-build',
|
|
110
|
+
feature: fname,
|
|
111
|
+
note: fname
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
|
|
68
115
|
Folder({ name: 'model/feature' }, () => {
|
|
69
116
|
Copy({
|
|
70
117
|
// TODO: these paths needs to be parameterised
|
|
71
|
-
from: BASE + '/project/.sdk/model/feature/' +
|
|
118
|
+
from: BASE + '/project/.sdk/model/feature/' + fname + '.jsonic',
|
|
72
119
|
exclude: true
|
|
73
120
|
})
|
|
121
|
+
File({ name: 'feature-index.jsonic' }, () => UpdateIndex({
|
|
122
|
+
content: ctx$.meta.content.feature_index,
|
|
123
|
+
names: features,
|
|
124
|
+
}))
|
|
74
125
|
})
|
|
75
126
|
|
|
76
127
|
each(target, (target) =>
|
|
77
|
-
Folder({ name: 'tm/' + target.name + '/src/feature/' +
|
|
128
|
+
Folder({ name: 'tm/' + target.name + '/src/feature/' + fname }, () => {
|
|
129
|
+
const from = Path.join(
|
|
130
|
+
(target.base || Path.join(BASE, '/project/.sdk')),
|
|
131
|
+
'tm',
|
|
132
|
+
target.name,
|
|
133
|
+
'/src/feature/',
|
|
134
|
+
fname
|
|
135
|
+
)
|
|
136
|
+
|
|
78
137
|
Copy({
|
|
79
|
-
from: BASE + '/project/.sdk/tm/' + target.name + '/src/feature/' + name,
|
|
138
|
+
// from: BASE + '/project/.sdk/tm/' + target.name + '/src/feature/' + name,
|
|
139
|
+
from,
|
|
80
140
|
exclude: true
|
|
81
141
|
})
|
|
82
142
|
}))
|
|
83
143
|
|
|
144
|
+
log.info({
|
|
145
|
+
point: 'feature-done', feature: fname,
|
|
146
|
+
note: fname
|
|
147
|
+
})
|
|
84
148
|
})
|
|
85
149
|
})
|
|
86
150
|
|
|
87
|
-
modifyModel({
|
|
88
|
-
features,
|
|
89
|
-
model: ctx$.meta.model,
|
|
90
|
-
tree: ctx$.meta.tree,
|
|
91
|
-
fs: ctx$.fs
|
|
92
|
-
})
|
|
93
|
-
|
|
94
151
|
})
|
|
95
152
|
|
|
96
153
|
|
|
97
|
-
async function modifyModel({ features, model, tree, fs }: any) {
|
|
98
|
-
// TODO: This is a kludge.
|
|
99
|
-
// Aontu should provide option for as-is AST so that can be used
|
|
100
|
-
// to find injection point more reliably
|
|
101
|
-
|
|
102
|
-
const path = tree.url
|
|
103
|
-
let src = fs().readFileSync(path, 'utf8')
|
|
104
|
-
|
|
105
|
-
// Inject feature file references into model
|
|
106
|
-
features.sort().map((feature: string) => {
|
|
107
|
-
const lineRE =
|
|
108
|
-
new RegExp(`@"feature/${feature}.jsonic"`)
|
|
109
|
-
if (!src.match(lineRE)) {
|
|
110
|
-
src = src.replace(/(main:\s+sdk:\s+feature:\s+\{\s*\}\n)/, '$1' +
|
|
111
|
-
`@"feature/${feature}.jsonic"\n`)
|
|
112
|
-
}
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
fs().writeFileSync(path, src)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
154
|
export {
|
|
120
|
-
|
|
155
|
+
feature_add,
|
|
156
|
+
action_feature,
|
|
121
157
|
}
|
package/src/action/target.ts
CHANGED
|
@@ -1,25 +1,48 @@
|
|
|
1
1
|
|
|
2
|
+
import Path from 'node:path'
|
|
3
|
+
|
|
2
4
|
import {
|
|
3
|
-
Jostraca,
|
|
4
5
|
Project,
|
|
5
|
-
File,
|
|
6
6
|
Folder,
|
|
7
|
-
Content,
|
|
8
7
|
Copy,
|
|
8
|
+
File,
|
|
9
9
|
cmp,
|
|
10
10
|
each,
|
|
11
11
|
} from 'jostraca'
|
|
12
12
|
|
|
13
|
+
import { showChanges } from '@voxgig/util'
|
|
14
|
+
|
|
15
|
+
import { getelem } from '@voxgig/struct'
|
|
16
|
+
|
|
17
|
+
import type {
|
|
18
|
+
ActionContext,
|
|
19
|
+
ActionResult,
|
|
20
|
+
} from '../types'
|
|
13
21
|
|
|
14
22
|
import { SdkGenError } from '../utility'
|
|
15
23
|
|
|
24
|
+
import {
|
|
25
|
+
feature_add
|
|
26
|
+
} from './feature'
|
|
27
|
+
|
|
28
|
+
import {
|
|
29
|
+
UpdateIndex,
|
|
30
|
+
loadContent,
|
|
31
|
+
} from './action'
|
|
32
|
+
|
|
16
33
|
|
|
17
34
|
const CMD_MAP: any = {
|
|
18
35
|
add: cmd_target_add
|
|
19
36
|
}
|
|
20
37
|
|
|
21
|
-
async function action_target(args: any[], ctx: any) {
|
|
22
38
|
|
|
39
|
+
type Target = {
|
|
40
|
+
origin: string
|
|
41
|
+
name: string
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
async function action_target(args: string[], actx: ActionContext): Promise<ActionResult> {
|
|
23
46
|
const cmdname = args[1]
|
|
24
47
|
|
|
25
48
|
const cmd = CMD_MAP[cmdname]
|
|
@@ -28,106 +51,203 @@ async function action_target(args: any[], ctx: any) {
|
|
|
28
51
|
throw new SdkGenError('Unknown target cmd: ' + cmdname)
|
|
29
52
|
}
|
|
30
53
|
|
|
31
|
-
await cmd(args,
|
|
54
|
+
return await cmd(args, actx)
|
|
32
55
|
}
|
|
33
56
|
|
|
34
57
|
|
|
35
|
-
async function cmd_target_add(args:
|
|
58
|
+
async function cmd_target_add(args: string[], actx: ActionContext): Promise<ActionResult> {
|
|
59
|
+
const targets_arg = args[2]
|
|
60
|
+
const targets: string[] =
|
|
61
|
+
'string' === typeof targets_arg ? targets_arg.split(',') : targets_arg
|
|
62
|
+
|
|
63
|
+
return target_add(targets, actx)
|
|
64
|
+
}
|
|
36
65
|
|
|
37
|
-
let targets = args[2]
|
|
38
|
-
targets = 'string' === typeof targets ? targets.split(',') : targets
|
|
39
66
|
|
|
40
|
-
|
|
67
|
+
// Code API
|
|
68
|
+
async function target_add(targets: string[], actx: ActionContext): Promise<ActionResult> {
|
|
69
|
+
// const jostraca = Jostraca()
|
|
70
|
+
const jostraca = actx.jostraca
|
|
41
71
|
|
|
42
72
|
const opts = {
|
|
43
|
-
fs:
|
|
44
|
-
folder:
|
|
45
|
-
log:
|
|
46
|
-
meta: {
|
|
47
|
-
|
|
73
|
+
fs: actx.fs,
|
|
74
|
+
folder: actx.folder,
|
|
75
|
+
log: actx.log.child({ cmp: 'jostraca' }),
|
|
76
|
+
meta: {
|
|
77
|
+
// model: actx.model,
|
|
78
|
+
tree: actx.tree,
|
|
79
|
+
content: loadContent(actx, 'target')
|
|
80
|
+
},
|
|
81
|
+
model: actx.model,
|
|
48
82
|
}
|
|
49
83
|
|
|
50
|
-
|
|
84
|
+
opts.log.info({
|
|
85
|
+
point: 'target-start',
|
|
86
|
+
note: (actx.opts.dryrun ? '** DRY RUN **' : '')
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
const jres = await jostraca.generate(opts, () => TargetRoot({ targets, actx }))
|
|
91
|
+
|
|
92
|
+
showChanges(opts.log, 'target-result', jres)
|
|
51
93
|
|
|
94
|
+
const features = Object.keys(actx.model.main.sdk.feature)
|
|
95
|
+
await feature_add(features, actx)
|
|
96
|
+
|
|
97
|
+
opts.log.info({
|
|
98
|
+
point: 'target-end',
|
|
99
|
+
note: (actx.opts.dryrun ? '** DRY RUN **' : '')
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
jres
|
|
104
|
+
}
|
|
52
105
|
}
|
|
53
106
|
|
|
54
107
|
|
|
55
108
|
const TargetRoot = cmp(function TargetRoot(props: any) {
|
|
56
109
|
const { ctx$, targets } = props
|
|
110
|
+
const { model, log } = ctx$
|
|
57
111
|
|
|
58
|
-
// TODO:
|
|
59
|
-
//
|
|
60
|
-
|
|
61
|
-
// console.log('MODEL')
|
|
62
|
-
// console.dir(ctx$.model, { depth: null })
|
|
63
|
-
|
|
64
|
-
const { model } = ctx$
|
|
112
|
+
// TODO: jostraca - make from value easier to specify
|
|
113
|
+
// const tfolder = 'node_modules/@voxgig/sdkgen/project/.sdk'
|
|
65
114
|
|
|
66
115
|
Project({}, () => {
|
|
67
116
|
each(targets, (n) => {
|
|
68
|
-
|
|
69
|
-
|
|
117
|
+
const tref = n.val$
|
|
118
|
+
|
|
119
|
+
log.info({
|
|
120
|
+
point: 'target-build',
|
|
121
|
+
target: tref,
|
|
122
|
+
note: tref
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
const { tname, tfolder, torigname, base } = resolveTarget(tref, ctx$)
|
|
126
|
+
const targetNote = tname + (tname != tref ? ' ref:' + tref : '')
|
|
127
|
+
|
|
128
|
+
log.info({
|
|
129
|
+
point: 'target-name', name: tname, folder: tfolder,
|
|
130
|
+
target: tref,
|
|
131
|
+
tname,
|
|
132
|
+
note: tname + (tname != torigname ? 'original' + torigname : '') + ' from:' + tfolder
|
|
133
|
+
})
|
|
70
134
|
|
|
71
135
|
Folder({ name: 'model/target' }, () => {
|
|
72
136
|
Copy({
|
|
73
|
-
from: '
|
|
137
|
+
from: tfolder + '/model/target/' + torigname + '.jsonic',
|
|
74
138
|
// exclude: true
|
|
139
|
+
replace: {
|
|
140
|
+
"'BASE'": "'" + base + "'"
|
|
141
|
+
}
|
|
75
142
|
})
|
|
143
|
+
File({ name: 'target-index.jsonic' }, () => UpdateIndex({
|
|
144
|
+
content: ctx$.meta.content.target_index,
|
|
145
|
+
// names: targets,
|
|
146
|
+
names: [tname]
|
|
147
|
+
}))
|
|
76
148
|
})
|
|
77
149
|
|
|
78
|
-
Folder({ name: 'src/cmp/' +
|
|
150
|
+
Folder({ name: 'src/cmp/' + tname }, () => {
|
|
79
151
|
Copy({
|
|
80
|
-
from: '
|
|
152
|
+
from: tfolder + '/src/cmp/' + torigname,
|
|
81
153
|
// exclude: true
|
|
82
154
|
})
|
|
83
155
|
})
|
|
84
156
|
|
|
85
|
-
Folder({ name: 'tm/' +
|
|
157
|
+
Folder({ name: 'tm/' + tname }, () => {
|
|
86
158
|
Copy({
|
|
87
|
-
from: '
|
|
159
|
+
from: tfolder + '/tm/' + torigname,
|
|
88
160
|
exclude: [/src\/feature/],
|
|
89
161
|
replace: {
|
|
90
|
-
|
|
162
|
+
|
|
163
|
+
// TODO: standard replacements
|
|
164
|
+
ProjectName: model.const.Name,
|
|
91
165
|
}
|
|
92
166
|
})
|
|
167
|
+
|
|
168
|
+
Folder({ name: 'src/feature' }, () => {
|
|
169
|
+
Copy({ from: tfolder + '/tm/' + torigname + '/src/feature/README.md' })
|
|
170
|
+
|
|
171
|
+
Folder({ name: 'base' }, () => {
|
|
172
|
+
Copy({ from: tfolder + '/tm/' + torigname + '/src/feature/base' })
|
|
173
|
+
})
|
|
174
|
+
})
|
|
93
175
|
})
|
|
94
176
|
|
|
177
|
+
log.info({
|
|
178
|
+
point: 'target-done', target: tref, note: targetNote
|
|
179
|
+
})
|
|
95
180
|
|
|
96
181
|
})
|
|
97
182
|
})
|
|
183
|
+
})
|
|
98
184
|
|
|
99
|
-
modifyModel({
|
|
100
|
-
targets,
|
|
101
|
-
model: ctx$.meta.model,
|
|
102
|
-
tree: ctx$.meta.tree,
|
|
103
|
-
fs: ctx$.fs
|
|
104
|
-
})
|
|
105
185
|
|
|
106
|
-
|
|
186
|
+
function resolveTarget(tref: string, ctx$: any) {
|
|
187
|
+
let tname = tref
|
|
188
|
+
let torigname = tref
|
|
189
|
+
let tfolder = 'node_modules/@voxgig/sdkgen/project/.sdk'
|
|
107
190
|
|
|
191
|
+
const root = ctx$.folder
|
|
192
|
+
const fs = ctx$.fs()
|
|
108
193
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
// Aontu should provide option for as-is AST so that can be used
|
|
112
|
-
// to find injection point more reliably
|
|
194
|
+
let fulltfolder = Path.normalize(Path.join(root, tfolder))
|
|
195
|
+
tname = getelem(tref.split('/'), -1)
|
|
113
196
|
|
|
114
|
-
|
|
115
|
-
|
|
197
|
+
let aliasref = tref
|
|
198
|
+
torigname = getelem(aliasref.split('/'), -1)
|
|
199
|
+
const aliasing = tref.split('~')
|
|
200
|
+
if (1 < aliasing.length) {
|
|
201
|
+
aliasref = aliasing[0]
|
|
202
|
+
tname = aliasing.slice(1).join('~')
|
|
203
|
+
torigname = getelem(aliasref.split('/'), -1)
|
|
204
|
+
}
|
|
116
205
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
206
|
+
const search: string[] = []
|
|
207
|
+
let found = false
|
|
208
|
+
if (aliasref.includes('/')) {
|
|
209
|
+
// NOTE: the last path element of the ref is the target name, not a folder.
|
|
210
|
+
const aliasbase = Path.dirname(aliasref)
|
|
211
|
+
|
|
212
|
+
if (!aliasref.startsWith('/')) {
|
|
213
|
+
fulltfolder = Path.normalize(Path.join(root, 'node_modules', aliasbase, '.sdk'))
|
|
214
|
+
search.push(fulltfolder)
|
|
215
|
+
found = fs.existsSync(fulltfolder)
|
|
216
|
+
|
|
217
|
+
if (!found) {
|
|
218
|
+
fulltfolder = Path.normalize(Path.join(root, aliasbase, '.sdk'))
|
|
219
|
+
search.push(fulltfolder)
|
|
220
|
+
found = fs.existsSync(fulltfolder)
|
|
221
|
+
}
|
|
124
222
|
}
|
|
125
|
-
|
|
223
|
+
else {
|
|
224
|
+
fulltfolder = Path.normalize(Path.join(aliasbase, '.sdk'))
|
|
225
|
+
search.push(fulltfolder)
|
|
226
|
+
found = fs.existsSync(fulltfolder)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
else {
|
|
230
|
+
search.push(fulltfolder)
|
|
231
|
+
found = fs.existsSync(fulltfolder)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
if (!found) {
|
|
235
|
+
throw new Error('Target folder not found in:\n' + search.join('\n '))
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const rootslash = root.endsWith('/') ? root : root + '/'
|
|
239
|
+
const out = {
|
|
240
|
+
tname,
|
|
241
|
+
tfolder: fulltfolder,
|
|
242
|
+
torigname,
|
|
243
|
+
base: fulltfolder.replace(rootslash, '')
|
|
244
|
+
}
|
|
126
245
|
|
|
127
|
-
|
|
246
|
+
return out
|
|
128
247
|
}
|
|
129
248
|
|
|
130
249
|
|
|
131
250
|
export {
|
|
132
|
-
action_target
|
|
251
|
+
action_target,
|
|
252
|
+
target_add,
|
|
133
253
|
}
|
package/src/cmp/Entity.ts
CHANGED
|
@@ -8,11 +8,17 @@ import { requirePath } from '../utility'
|
|
|
8
8
|
|
|
9
9
|
const Entity = cmp(function Entity(props: any) {
|
|
10
10
|
const { target, entity, ctx$ } = props
|
|
11
|
+
const { log } = ctx$
|
|
11
12
|
|
|
12
13
|
const entitySDK = ctx$.model.main.sdk.entity[entity.name]
|
|
13
14
|
|
|
14
15
|
const Entity_sdk = requirePath(ctx$, `./cmp/${target.name}/Entity_${target.name}`)
|
|
15
16
|
Entity_sdk['Entity']({ target, entity, entitySDK })
|
|
17
|
+
|
|
18
|
+
log.info({
|
|
19
|
+
point: 'generate-entity', target, entity,
|
|
20
|
+
note: 'target:' + target.name + ', ' + 'entity: ' + entity.name
|
|
21
|
+
})
|
|
16
22
|
})
|
|
17
23
|
|
|
18
24
|
|
package/src/cmp/Feature.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
|
|
2
2
|
import { cmp, Copy, Folder } from 'jostraca'
|
|
3
3
|
|
|
4
|
-
import { resolvePath } from '../utility'
|
|
5
|
-
|
|
6
|
-
|
|
7
4
|
const Feature = cmp(function Feature(props: any) {
|
|
8
5
|
const { target, feature, ctx$ } = props
|
|
6
|
+
const { log } = ctx$
|
|
9
7
|
|
|
10
8
|
Folder({ name: 'src/feature/' + feature.name }, () => {
|
|
11
9
|
// TODO: Copy should just warn if from not found
|
|
@@ -18,6 +16,11 @@ const Feature = cmp(function Feature(props: any) {
|
|
|
18
16
|
})
|
|
19
17
|
})
|
|
20
18
|
|
|
19
|
+
log.info({
|
|
20
|
+
point: 'generate-feature', target, feature,
|
|
21
|
+
note: 'target:' + target.name + ', ' + 'feature: ' + feature.name
|
|
22
|
+
})
|
|
23
|
+
|
|
21
24
|
})
|
|
22
25
|
|
|
23
26
|
|