@voxgig/sdkgen 3.4.6 → 3.5.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.
Files changed (198) hide show
  1. package/bin/voxgig-sdkgen +78 -10
  2. package/dist/action/action.d.ts +5 -2
  3. package/dist/action/action.js +113 -6
  4. package/dist/action/action.js.map +1 -1
  5. package/dist/action/check.d.ts +15 -0
  6. package/dist/action/check.js +347 -0
  7. package/dist/action/check.js.map +1 -0
  8. package/dist/action/dispatch.d.ts +8 -0
  9. package/dist/action/dispatch.js +74 -0
  10. package/dist/action/dispatch.js.map +1 -0
  11. package/dist/action/docs.d.ts +4 -0
  12. package/dist/action/docs.js +236 -0
  13. package/dist/action/docs.js.map +1 -0
  14. package/dist/action/doctor.d.ts +5 -2
  15. package/dist/action/doctor.js +526 -74
  16. package/dist/action/doctor.js.map +1 -1
  17. package/dist/action/feature.js +96 -17
  18. package/dist/action/feature.js.map +1 -1
  19. package/dist/action/kind.d.ts +30 -0
  20. package/dist/action/kind.js +258 -0
  21. package/dist/action/kind.js.map +1 -0
  22. package/dist/action/package.d.ts +25 -0
  23. package/dist/action/package.js +852 -0
  24. package/dist/action/package.js.map +1 -0
  25. package/dist/action/resolve.d.ts +18 -0
  26. package/dist/action/resolve.js +280 -0
  27. package/dist/action/resolve.js.map +1 -0
  28. package/dist/action/target.d.ts +7 -1
  29. package/dist/action/target.js +240 -97
  30. package/dist/action/target.js.map +1 -1
  31. package/dist/cmp/Docs.d.ts +4 -0
  32. package/dist/cmp/Docs.js +98 -0
  33. package/dist/cmp/Docs.js.map +1 -0
  34. package/dist/cmp/ExternalDocs.d.ts +2 -0
  35. package/dist/cmp/ExternalDocs.js +43 -0
  36. package/dist/cmp/ExternalDocs.js.map +1 -0
  37. package/dist/cmp/ReadmeTop.js +5 -1
  38. package/dist/cmp/ReadmeTop.js.map +1 -1
  39. package/dist/helpers/definition.d.ts +5 -0
  40. package/dist/helpers/definition.js +72 -0
  41. package/dist/helpers/definition.js.map +1 -0
  42. package/dist/helpers/featureSource.d.ts +8 -2
  43. package/dist/helpers/featureSource.js +61 -12
  44. package/dist/helpers/featureSource.js.map +1 -1
  45. package/dist/helpers/junk.d.ts +11 -0
  46. package/dist/helpers/junk.js +149 -0
  47. package/dist/helpers/junk.js.map +1 -0
  48. package/dist/helpers/manifest.d.ts +50 -0
  49. package/dist/helpers/manifest.js +328 -0
  50. package/dist/helpers/manifest.js.map +1 -0
  51. package/dist/helpers/modelcheck.d.ts +22 -0
  52. package/dist/helpers/modelcheck.js +203 -0
  53. package/dist/helpers/modelcheck.js.map +1 -0
  54. package/dist/helpers/semver.d.ts +4 -0
  55. package/dist/helpers/semver.js +174 -0
  56. package/dist/helpers/semver.js.map +1 -0
  57. package/dist/helpers/shipped.d.ts +4 -0
  58. package/dist/helpers/shipped.js +36 -0
  59. package/dist/helpers/shipped.js.map +1 -0
  60. package/dist/helpers/stdrep.d.ts +9 -1
  61. package/dist/helpers/stdrep.js +22 -0
  62. package/dist/helpers/stdrep.js.map +1 -1
  63. package/dist/sdkgen.d.ts +15 -3
  64. package/dist/sdkgen.js +233 -67
  65. package/dist/sdkgen.js.map +1 -1
  66. package/dist/tsconfig.tsbuildinfo +1 -1
  67. package/dist/types.d.ts +10 -2
  68. package/dist/utility.js +17 -0
  69. package/dist/utility.js.map +1 -1
  70. package/model/sdkgen.aontu +69 -0
  71. package/package.json +3 -2
  72. package/project/.sdk/model/feature/audit.aontu +1 -0
  73. package/project/.sdk/model/feature/cache.aontu +1 -0
  74. package/project/.sdk/model/feature/clienttrack.aontu +1 -0
  75. package/project/.sdk/model/feature/debug.aontu +1 -0
  76. package/project/.sdk/model/feature/idempotency.aontu +1 -0
  77. package/project/.sdk/model/feature/log.aontu +1 -0
  78. package/project/.sdk/model/feature/metrics.aontu +1 -0
  79. package/project/.sdk/model/feature/netsim.aontu +1 -0
  80. package/project/.sdk/model/feature/paging.aontu +1 -0
  81. package/project/.sdk/model/feature/proxy.aontu +1 -0
  82. package/project/.sdk/model/feature/ratelimit.aontu +1 -0
  83. package/project/.sdk/model/feature/rbac.aontu +1 -0
  84. package/project/.sdk/model/feature/retry.aontu +1 -0
  85. package/project/.sdk/model/feature/streaming.aontu +1 -0
  86. package/project/.sdk/model/feature/telemetry.aontu +1 -0
  87. package/project/.sdk/model/feature/test.aontu +1 -0
  88. package/project/.sdk/model/feature/timeout.aontu +1 -0
  89. package/project/.sdk/model/target/c.aontu +1 -0
  90. package/project/.sdk/model/target/clojure.aontu +1 -0
  91. package/project/.sdk/model/target/cpp.aontu +1 -0
  92. package/project/.sdk/model/target/dart.aontu +1 -0
  93. package/project/.sdk/model/target/elixir.aontu +1 -0
  94. package/project/.sdk/model/target/go-cli.aontu +1 -0
  95. package/project/.sdk/model/target/go-mcp.aontu +1 -0
  96. package/project/.sdk/model/target/go.aontu +1 -0
  97. package/project/.sdk/model/target/haskell.aontu +1 -0
  98. package/project/.sdk/model/target/java.aontu +1 -0
  99. package/project/.sdk/model/target/js.aontu +1 -0
  100. package/project/.sdk/model/target/kotlin.aontu +1 -0
  101. package/project/.sdk/model/target/lean.aontu +1 -0
  102. package/project/.sdk/model/target/lua.aontu +1 -0
  103. package/project/.sdk/model/target/ocaml.aontu +1 -0
  104. package/project/.sdk/model/target/perl.aontu +1 -0
  105. package/project/.sdk/model/target/php.aontu +1 -0
  106. package/project/.sdk/model/target/py-data.aontu +1 -0
  107. package/project/.sdk/model/target/py.aontu +1 -0
  108. package/project/.sdk/model/target/rb.aontu +1 -0
  109. package/project/.sdk/model/target/rust.aontu +1 -0
  110. package/project/.sdk/model/target/scala.aontu +1 -0
  111. package/project/.sdk/model/target/seneca-provider.aontu +1 -0
  112. package/project/.sdk/model/target/zig.aontu +1 -0
  113. package/project/.sdk/src/cmp/c/Config_c.ts +44 -0
  114. package/project/.sdk/src/cmp/c/fragment/Main.fragment.c +3 -1
  115. package/project/.sdk/src/cmp/clojure/Config_clojure.ts +37 -42
  116. package/project/.sdk/src/cmp/clojure/utility_clojure.ts +42 -0
  117. package/project/.sdk/src/cmp/cpp/Config_cpp.ts +18 -0
  118. package/project/.sdk/src/cmp/csharp/Config_csharp.ts +125 -52
  119. package/project/.sdk/src/cmp/csharp/fragment/Main.fragment.cs +3 -1
  120. package/project/.sdk/src/cmp/csharp/utility_csharp.ts +94 -6
  121. package/project/.sdk/src/cmp/dart/Config_dart.ts +56 -3
  122. package/project/.sdk/src/cmp/dart/fragment/Config.data.fragment.dart +74 -0
  123. package/project/.sdk/src/cmp/dart/fragment/Config.fragment.dart +6 -9
  124. package/project/.sdk/src/cmp/dart/fragment/Main.fragment.dart +16 -5
  125. package/project/.sdk/src/cmp/dart/utility_dart.ts +18 -0
  126. package/project/.sdk/src/cmp/elixir/Config_elixir.ts +128 -13
  127. package/project/.sdk/src/cmp/elixir/fragment/Main.fragment.ex +3 -1
  128. package/project/.sdk/src/cmp/elixir/utility_elixir.ts +6 -0
  129. package/project/.sdk/src/cmp/haskell/Config_haskell.ts +35 -52
  130. package/project/.sdk/src/cmp/haskell/Package_haskell.ts +1 -0
  131. package/project/.sdk/src/cmp/haskell/Test_haskell.ts +1 -1
  132. package/project/.sdk/src/cmp/haskell/utility_haskell.ts +15 -5
  133. package/project/.sdk/src/cmp/java/Config_java.ts +21 -0
  134. package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +15 -0
  135. package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +42 -39
  136. package/project/.sdk/src/cmp/perl/Config_perl.ts +15 -0
  137. package/project/.sdk/src/cmp/perl/fragment/Main.fragment.pm +3 -1
  138. package/project/.sdk/src/cmp/rust/Config_rust.ts +44 -0
  139. package/project/.sdk/src/cmp/rust/fragment/Main.fragment.rs +4 -2
  140. package/project/.sdk/src/cmp/scala/Config_scala.ts +15 -0
  141. package/project/.sdk/src/cmp/swift/Config_swift.ts +17 -0
  142. package/project/.sdk/src/cmp/swift/fragment/Main.fragment.swift +3 -1
  143. package/project/.sdk/src/cmp/zig/Config_zig.ts +44 -0
  144. package/project/.sdk/src/cmp/zig/TestEntity_zig.ts +9 -2
  145. package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +31 -18
  146. package/project/.sdk/tm/c/core/sdk.h +1 -0
  147. package/project/.sdk/tm/c/utility/make_options.c +5 -1
  148. package/project/.sdk/tm/clojure/src/sdk/core.clj +51 -3
  149. package/project/.sdk/tm/cpp/core/types.hpp +4 -1
  150. package/project/.sdk/tm/cpp/utility/pipeline.hpp +5 -1
  151. package/project/.sdk/tm/csharp/test/PipelineTest.cs +15 -0
  152. package/project/.sdk/tm/csharp/utility/MakeOptions.cs +67 -1
  153. package/project/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +43 -0
  154. package/project/.sdk/tm/elixir/lib/projectname/utility.ex +58 -2
  155. package/project/.sdk/tm/haskell/{test/TestJson.hs → src/SdkJson.hs} +8 -4
  156. package/project/.sdk/tm/haskell/src/SdkRuntime.hs +55 -2
  157. package/project/.sdk/tm/haskell/test/Runner.hs +1 -1
  158. package/project/.sdk/tm/haskell/test/StructCorpus.hs +1 -1
  159. package/project/.sdk/tm/java/core/SdkClient.java +3 -1
  160. package/project/.sdk/tm/java/utility/MakeOptions.java +5 -1
  161. package/project/.sdk/tm/kotlin/core/SdkClient.kt +3 -1
  162. package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +5 -1
  163. package/project/.sdk/tm/ocaml/Makefile +3 -2
  164. package/project/.sdk/tm/ocaml/sdk_json.ml +106 -0
  165. package/project/.sdk/tm/ocaml/sdk_runtime.ml +56 -0
  166. package/project/.sdk/tm/ocaml/test/struct_corpus.ml +4 -86
  167. package/project/.sdk/tm/perl/utility/make_options.pm +5 -1
  168. package/project/.sdk/tm/rust/utility/make_options.rs +79 -1
  169. package/project/.sdk/tm/scala/core/SdkClient.scala +3 -1
  170. package/project/.sdk/tm/scala/utility/Make.scala +5 -1
  171. package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +5 -1
  172. package/project/.sdk/tm/zig/core/utility.zig +85 -1
  173. package/project/.sdk/tm/zig/test/gotcha_test.zig +8 -8
  174. package/project/sdkgen-package.json +57 -0
  175. package/src/action/action.ts +136 -6
  176. package/src/action/check.ts +495 -0
  177. package/src/action/dispatch.ts +105 -0
  178. package/src/action/docs.ts +310 -0
  179. package/src/action/doctor.ts +692 -81
  180. package/src/action/feature.ts +109 -17
  181. package/src/action/kind.ts +375 -0
  182. package/src/action/package.ts +1173 -0
  183. package/src/action/resolve.ts +362 -0
  184. package/src/action/target.ts +290 -108
  185. package/src/cmp/Docs.ts +125 -0
  186. package/src/cmp/ExternalDocs.ts +54 -0
  187. package/src/cmp/ReadmeTop.ts +6 -1
  188. package/src/helpers/definition.ts +82 -0
  189. package/src/helpers/featureSource.ts +83 -13
  190. package/src/helpers/junk.ts +168 -0
  191. package/src/helpers/manifest.ts +474 -0
  192. package/src/helpers/modelcheck.ts +262 -0
  193. package/src/helpers/semver.ts +211 -0
  194. package/src/helpers/shipped.ts +41 -0
  195. package/src/helpers/stdrep.ts +70 -0
  196. package/src/sdkgen.ts +294 -66
  197. package/src/types.ts +33 -3
  198. package/src/utility.ts +17 -0
@@ -0,0 +1,310 @@
1
+ // `docs add <ref>` — the third kind. See docs/design/sdkgen-packages.md §20.
2
+ //
3
+ // WHAT A DOCS ITEM IS
4
+ //
5
+ // A generation target whose destination is a DOCUMENTATION SYSTEM rather than
6
+ // a language: a static site, a developer-portal catalogue, a hosted service's
7
+ // config. sdkgen ships the kind and no items; the items live in packages
8
+ // (`@voxgig/docgen` first), which is what makes the destinations someone
9
+ // else's business rather than a list this repo has to guess at.
10
+ //
11
+ // WHY IT IS NOT A TARGET
12
+ //
13
+ // Three reasons, argued in §20.2 and worth restating where the code is:
14
+ //
15
+ // - a docs item's INPUT is the target collection — a page per SDK, the
16
+ // package table, per-language tabs — so a docs item inside
17
+ // `main.kit.target` would enumerate itself;
18
+ // - `action/feature.ts` fans out with `each(target, …)` and warns
19
+ // `feature-source-missing` per target with no source, so a docs item in
20
+ // that collection would collect one warning per feature, forever
21
+ // (`srcfeature: false` does not help — that flag is read at generate time
22
+ // and never by the add-time fan-out);
23
+ // - `ext`, `comment: line` and `module: name` are required, non-defaulted
24
+ // strings in the target spread, and a site emitting `.md`, `.yml`, `.css`
25
+ // and `.svg` at once has no honest value for `comment.line`.
26
+ //
27
+ // WHAT THIS ACTION DOES, AND WHAT IT DELIBERATELY DOES NOT
28
+ //
29
+ // It installs the definition — through the shared spine, so provenance,
30
+ // aliasing and the index come along unchanged — and the kind's trees, whose
31
+ // paths come from the registry rather than being spelled here.
32
+ //
33
+ // It does NOT fan out over targets, trim, or prune. A docs item reads the
34
+ // target collection at GENERATE time, not at add time: the opposite direction
35
+ // and the opposite moment from a feature's fan-out, so sharing that machinery
36
+ // would have been a false economy.
37
+
38
+ import { cmp, each, Copy, Folder, Project } from 'jostraca'
39
+
40
+ import type {
41
+ ActionContext,
42
+ ActionResult,
43
+ } from '../types'
44
+
45
+ import { SdkGenError } from '../utility'
46
+
47
+ import { templateReplacements } from '../helpers/stdrep'
48
+
49
+ import { copyOpts } from '../helpers/junk'
50
+
51
+ import { resolveKind, kindModel, kindTrees } from './kind'
52
+ import type { TreeDef } from './kind'
53
+
54
+ import { registerInstalled } from './resolve'
55
+
56
+ import { aliasCmpTree, pruneStaleTemplates } from './target'
57
+
58
+ import { parseAddNames, loadContent, ensureModelInclude } from './action'
59
+
60
+
61
+ // The PREFIX of a docs item's component tree (`src/cmp/docs/`), for the
62
+ // alias rewrite. Derived from the registry's declaration rather than written
63
+ // out a second time, so the two cannot disagree about where docs components
64
+ // live.
65
+ const NAME_MARK = '\u0001name\u0001'
66
+
67
+ function cmpBase(): string {
68
+ const cmp = kindTrees('docs', NAME_MARK)
69
+ .find((t: TreeDef) => 'none' === t.replace)
70
+
71
+ return null == cmp ? 'src/cmp/docs/' : cmp.path.split(NAME_MARK)[0]
72
+ }
73
+
74
+
75
+ const CMD_MAP: any = Object.assign(Object.create(null), {
76
+ add: cmd_docs_add,
77
+ })
78
+
79
+
80
+ async function action_docs(
81
+ args: string[], actx: ActionContext,
82
+ ): Promise<ActionResult> {
83
+ const cmdname = args[1]
84
+ const cmd = CMD_MAP[cmdname]
85
+
86
+ if (null == cmd) {
87
+ throw new SdkGenError(
88
+ 'Unknown docs cmd: ' + cmdname + ' (expected: ' +
89
+ Object.keys(CMD_MAP).sort().join(', ') + ')')
90
+ }
91
+
92
+ return await cmd(args, actx)
93
+ }
94
+
95
+
96
+ async function cmd_docs_add(
97
+ args: string[], actx: ActionContext,
98
+ ): Promise<ActionResult> {
99
+ return docs_add(parseAddNames(args), actx)
100
+ }
101
+
102
+
103
+ // Code API.
104
+ async function docs_add(
105
+ docs: string[], actx: ActionContext,
106
+ ): Promise<ActionResult> {
107
+ const jostraca = actx.jostraca
108
+
109
+ const opts = {
110
+ fs: actx.fs,
111
+ folder: actx.folder,
112
+ log: actx.log.child({ cmp: 'jostraca' }),
113
+ meta: {
114
+ url: actx.url,
115
+ // Seeded: no project scaffolded before the docs kind existed has a
116
+ // docs index, and every project alive today is in that position.
117
+ content: loadContent(actx, 'docs', { docs: '# Docs\n' }),
118
+ },
119
+ model: actx.model,
120
+ // Per-call, never left to the Jostraca instance: `generate` runs its own
121
+ // options through OptionsShape first, which fills `control.dryrun: false`
122
+ // and would override the instance flag. The same trap target_add
123
+ // documents.
124
+ control: {
125
+ dryrun: !!actx.opts.dryrun
126
+ },
127
+ // Per-call for the same reason, and covering the same accident: see
128
+ // helpers/junk.
129
+ cmp: copyOpts(),
130
+ }
131
+
132
+ opts.log.info({
133
+ point: 'docs-start',
134
+ note: (actx.opts.dryrun ? '** DRY RUN **' : '')
135
+ })
136
+
137
+ // PREFLIGHT, before a single file is written.
138
+ //
139
+ // The write pass emits the definition and its index entry before it copies
140
+ // the trees, so a ref whose definition exists but whose required components
141
+ // do not left the command failed AND the project carrying a docs item with
142
+ // no implementation — which the next model compile then reads as real.
143
+ // `package add` already validates a whole package up front for exactly this
144
+ // reason; a direct `docs add` needs the same guarantee.
145
+ preflight(docs, actx)
146
+
147
+ // The project's own model must INCLUDE the docs index, or everything below
148
+ // is invisible: no project scaffolded before this kind existed includes it,
149
+ // and `main.kit.docs` would simply be absent from the next compile.
150
+ ensureModelInclude(actx, 'docs')
151
+
152
+ // Into the IN-MEMORY model before anything reads it. Nothing recompiles
153
+ // `model/sdk.aontu` mid-process, so without this a second docs item in the
154
+ // same command — and anything else later in it — behaves as if the first
155
+ // was never installed. One definition of what gets recorded, shared with
156
+ // `target add` and `package add`.
157
+ registerInstalled('docs', docs, actx)
158
+
159
+ const jres = await jostraca.generate(opts, () =>
160
+ DocsRoot({ docs, actx }))
161
+
162
+ return { jres }
163
+ }
164
+
165
+
166
+ // Resolve every ref and check every REQUIRED tree, throwing before anything
167
+ // is written. Resolution itself is the other half: a ref that names no
168
+ // definition fails here rather than partway through the pass.
169
+ function preflight(docs: string[], actx: ActionContext) {
170
+ const fs = actx.fs()
171
+
172
+ for (const ref of docs) {
173
+ const source = resolveKind(ref, 'docs', actx as any)
174
+
175
+ for (const tree of kindTrees('docs', source.origname)) {
176
+ if (!tree.required) {
177
+ continue
178
+ }
179
+
180
+ const from = source.folder + '/' + tree.path
181
+
182
+ if (!fs.existsSync(from)) {
183
+ throw new SdkGenError(
184
+ 'Docs ' + source.name + ': required tree not found: ' + from +
185
+ '\n a docs item needs its components (' + tree.path +
186
+ '); nothing has been written')
187
+ }
188
+ }
189
+ }
190
+ }
191
+
192
+
193
+ const DocsRoot = cmp(function DocsRoot(props: any) {
194
+ const { ctx$, docs } = props
195
+ const { log } = ctx$
196
+
197
+ Project({}, () => {
198
+ // Every installed name seen so far in this run: the index File is
199
+ // re-rendered per item and the last render wins, so each render has to
200
+ // carry all of them.
201
+ const dnames: string[] = []
202
+
203
+ each(docs, (n: any) => {
204
+ const dref = n.val$
205
+
206
+ log.info({ point: 'docs-build', docs: dref, note: dref })
207
+
208
+ // The shared spine: a BARE name resolves against what the model
209
+ // RECORDS, so a docs item installed from a package resolves back to
210
+ // that package on its next add rather than to the bundled scaffold.
211
+ const source = resolveKind(dref, 'docs', ctx$)
212
+
213
+ dnames.push(source.name)
214
+
215
+ log.info({
216
+ point: 'docs-name', docs: source.name, folder: source.folder, ref: dref,
217
+ note: source.name +
218
+ (source.name !== source.origname ?
219
+ ' (from ' + source.origname + ')' : '') +
220
+ ' from:' + source.folder
221
+ })
222
+
223
+ Folder({ name: 'model/docs' }, () => kindModel({
224
+ ctx$, kind: 'docs', source, names: dnames,
225
+ content: ctx$.meta.content.docs_index,
226
+ }))
227
+
228
+ // Both ends of every tree come from the registry's ONE declaration,
229
+ // resolved twice: the source carries the ORIGIN name, the destination
230
+ // the installed one. Deriving the source path by substituting inside
231
+ // the destination path would corrupt any item whose name also appears
232
+ // in the fixed part of the path.
233
+ const dest = kindTrees('docs', source.name)
234
+ const from = kindTrees('docs', source.origname)
235
+
236
+ dest.forEach((tree: TreeDef, i: number) => {
237
+ // Copy only ADDS and overwrites. A newer version of the package that
238
+ // RETIRED a template would leave the old one behind, generating from
239
+ // it forever — the failure `pruneStaleTemplates` exists for, and the
240
+ // reason 30 repos once carried a superseded harness file.
241
+ //
242
+ // Templates only, exactly as `target add` prunes only `tm`: extra
243
+ // files under a component tree are the project's own (doctor calls
244
+ // them `additive`, and adding a component is the supported way to
245
+ // extend an item), so pruning there would delete supported work.
246
+ if ('template' === tree.replace) {
247
+ pruneStaleTemplates(
248
+ ctx$, source.folder + '/' + from[i].path, tree.path, [],
249
+ !!props.actx?.opts?.dryrun)
250
+ }
251
+
252
+ copyTree(ctx$, source, tree, from[i].path)
253
+ })
254
+
255
+ log.info({ point: 'docs-done', docs: source.name, note: source.name })
256
+ })
257
+ })
258
+ })
259
+
260
+
261
+ // One tree, copied from the origin path to the installed one.
262
+ //
263
+ // An optional tree the source does not ship is simply not copied — that is
264
+ // what `required: false` means, and a docs item whose every byte is generated
265
+ // legitimately has no template tree.
266
+ function copyTree(ctx$: any, source: any, tree: TreeDef, frompath: string) {
267
+ const fs = ctx$.fs()
268
+ const from = source.folder + '/' + frompath
269
+
270
+ if (!fs.existsSync(from)) {
271
+ if (tree.required) {
272
+ throw new SdkGenError(
273
+ 'Docs ' + source.name + ': required tree not found: ' + from)
274
+ }
275
+
276
+ ctx$.log.info({
277
+ point: 'docs-tree-absent', docs: source.name, tree: tree.path, from,
278
+ note: source.name + ': the source ships no ' + frompath +
279
+ ', nothing to copy'
280
+ })
281
+ return
282
+ }
283
+
284
+ // An ALIASED component tree cannot be copied verbatim: components are
285
+ // dispatched by the convention `cmp/docs/<n>/Main_<n>`, so files keeping
286
+ // the origin suffix resolve nothing — `Main_apidocs.ts` is invisible to a
287
+ // lookup for `Main_portal`. Same rule as a target's, so the same function
288
+ // does it; jostraca's tree Copy has no per-entry rename hook, which is why
289
+ // an aliased tree is emitted file by file.
290
+ if (source.name !== source.origname && 'none' === tree.replace) {
291
+ aliasCmpTree(ctx$, from, tree.path, source.origname, source.name,
292
+ cmpBase())
293
+ return
294
+ }
295
+
296
+ Folder({ name: tree.path }, () => {
297
+ Copy({
298
+ from,
299
+ // Shared with doctor, which re-applies them before comparing.
300
+ ...('template' === tree.replace ?
301
+ { replace: templateReplacements(ctx$.model, source.name) } : {}),
302
+ })
303
+ })
304
+ }
305
+
306
+
307
+ export {
308
+ action_docs,
309
+ docs_add,
310
+ }