@voxgig/sdkgen 3.4.7 → 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.
- package/bin/voxgig-sdkgen +78 -10
- package/dist/action/action.d.ts +5 -2
- package/dist/action/action.js +113 -6
- package/dist/action/action.js.map +1 -1
- package/dist/action/check.d.ts +15 -0
- package/dist/action/check.js +347 -0
- package/dist/action/check.js.map +1 -0
- package/dist/action/dispatch.d.ts +8 -0
- package/dist/action/dispatch.js +74 -0
- package/dist/action/dispatch.js.map +1 -0
- package/dist/action/docs.d.ts +4 -0
- package/dist/action/docs.js +236 -0
- package/dist/action/docs.js.map +1 -0
- package/dist/action/doctor.d.ts +5 -2
- package/dist/action/doctor.js +526 -74
- package/dist/action/doctor.js.map +1 -1
- package/dist/action/feature.js +96 -17
- package/dist/action/feature.js.map +1 -1
- package/dist/action/kind.d.ts +30 -0
- package/dist/action/kind.js +258 -0
- package/dist/action/kind.js.map +1 -0
- package/dist/action/package.d.ts +25 -0
- package/dist/action/package.js +852 -0
- package/dist/action/package.js.map +1 -0
- package/dist/action/resolve.d.ts +18 -0
- package/dist/action/resolve.js +280 -0
- package/dist/action/resolve.js.map +1 -0
- package/dist/action/target.d.ts +7 -1
- package/dist/action/target.js +240 -97
- package/dist/action/target.js.map +1 -1
- package/dist/cmp/Docs.d.ts +4 -0
- package/dist/cmp/Docs.js +98 -0
- package/dist/cmp/Docs.js.map +1 -0
- package/dist/cmp/ExternalDocs.d.ts +2 -0
- package/dist/cmp/ExternalDocs.js +43 -0
- package/dist/cmp/ExternalDocs.js.map +1 -0
- package/dist/helpers/definition.d.ts +5 -0
- package/dist/helpers/definition.js +72 -0
- package/dist/helpers/definition.js.map +1 -0
- package/dist/helpers/featureSource.d.ts +8 -2
- package/dist/helpers/featureSource.js +61 -12
- package/dist/helpers/featureSource.js.map +1 -1
- package/dist/helpers/junk.d.ts +11 -0
- package/dist/helpers/junk.js +149 -0
- package/dist/helpers/junk.js.map +1 -0
- package/dist/helpers/manifest.d.ts +50 -0
- package/dist/helpers/manifest.js +328 -0
- package/dist/helpers/manifest.js.map +1 -0
- package/dist/helpers/modelcheck.d.ts +22 -0
- package/dist/helpers/modelcheck.js +203 -0
- package/dist/helpers/modelcheck.js.map +1 -0
- package/dist/helpers/semver.d.ts +4 -0
- package/dist/helpers/semver.js +174 -0
- package/dist/helpers/semver.js.map +1 -0
- package/dist/helpers/shipped.d.ts +4 -0
- package/dist/helpers/shipped.js +36 -0
- package/dist/helpers/shipped.js.map +1 -0
- package/dist/helpers/stdrep.d.ts +9 -1
- package/dist/helpers/stdrep.js +22 -0
- package/dist/helpers/stdrep.js.map +1 -1
- package/dist/sdkgen.d.ts +15 -3
- package/dist/sdkgen.js +233 -67
- package/dist/sdkgen.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/types.d.ts +10 -2
- package/dist/utility.js +17 -0
- package/dist/utility.js.map +1 -1
- package/model/sdkgen.aontu +69 -0
- package/package.json +3 -2
- package/project/.sdk/model/feature/audit.aontu +1 -0
- package/project/.sdk/model/feature/cache.aontu +1 -0
- package/project/.sdk/model/feature/clienttrack.aontu +1 -0
- package/project/.sdk/model/feature/debug.aontu +1 -0
- package/project/.sdk/model/feature/idempotency.aontu +1 -0
- package/project/.sdk/model/feature/log.aontu +1 -0
- package/project/.sdk/model/feature/metrics.aontu +1 -0
- package/project/.sdk/model/feature/netsim.aontu +1 -0
- package/project/.sdk/model/feature/paging.aontu +1 -0
- package/project/.sdk/model/feature/proxy.aontu +1 -0
- package/project/.sdk/model/feature/ratelimit.aontu +1 -0
- package/project/.sdk/model/feature/rbac.aontu +1 -0
- package/project/.sdk/model/feature/retry.aontu +1 -0
- package/project/.sdk/model/feature/streaming.aontu +1 -0
- package/project/.sdk/model/feature/telemetry.aontu +1 -0
- package/project/.sdk/model/feature/test.aontu +1 -0
- package/project/.sdk/model/feature/timeout.aontu +1 -0
- package/project/.sdk/model/target/c.aontu +1 -0
- package/project/.sdk/model/target/clojure.aontu +1 -0
- package/project/.sdk/model/target/cpp.aontu +1 -0
- package/project/.sdk/model/target/dart.aontu +1 -0
- package/project/.sdk/model/target/elixir.aontu +1 -0
- package/project/.sdk/model/target/go-cli.aontu +1 -0
- package/project/.sdk/model/target/go-mcp.aontu +1 -0
- package/project/.sdk/model/target/go.aontu +1 -0
- package/project/.sdk/model/target/haskell.aontu +1 -0
- package/project/.sdk/model/target/java.aontu +1 -0
- package/project/.sdk/model/target/js.aontu +1 -0
- package/project/.sdk/model/target/kotlin.aontu +1 -0
- package/project/.sdk/model/target/lean.aontu +1 -0
- package/project/.sdk/model/target/lua.aontu +1 -0
- package/project/.sdk/model/target/ocaml.aontu +1 -0
- package/project/.sdk/model/target/perl.aontu +1 -0
- package/project/.sdk/model/target/php.aontu +1 -0
- package/project/.sdk/model/target/py-data.aontu +1 -0
- package/project/.sdk/model/target/py.aontu +1 -0
- package/project/.sdk/model/target/rb.aontu +1 -0
- package/project/.sdk/model/target/rust.aontu +1 -0
- package/project/.sdk/model/target/scala.aontu +1 -0
- package/project/.sdk/model/target/seneca-provider.aontu +1 -0
- package/project/.sdk/model/target/zig.aontu +1 -0
- package/project/.sdk/src/cmp/c/Config_c.ts +44 -0
- package/project/.sdk/src/cmp/c/fragment/Main.fragment.c +3 -1
- package/project/.sdk/src/cmp/clojure/Config_clojure.ts +37 -42
- package/project/.sdk/src/cmp/clojure/utility_clojure.ts +42 -0
- package/project/.sdk/src/cmp/cpp/Config_cpp.ts +18 -0
- package/project/.sdk/src/cmp/csharp/Config_csharp.ts +125 -52
- package/project/.sdk/src/cmp/csharp/fragment/Main.fragment.cs +3 -1
- package/project/.sdk/src/cmp/csharp/utility_csharp.ts +94 -6
- package/project/.sdk/src/cmp/dart/Config_dart.ts +43 -5
- package/project/.sdk/src/cmp/dart/fragment/Config.data.fragment.dart +74 -0
- package/project/.sdk/src/cmp/dart/fragment/Config.fragment.dart +6 -9
- package/project/.sdk/src/cmp/dart/fragment/Main.fragment.dart +16 -5
- package/project/.sdk/src/cmp/dart/utility_dart.ts +18 -0
- package/project/.sdk/src/cmp/elixir/Config_elixir.ts +128 -13
- package/project/.sdk/src/cmp/elixir/fragment/Main.fragment.ex +3 -1
- package/project/.sdk/src/cmp/elixir/utility_elixir.ts +6 -0
- package/project/.sdk/src/cmp/haskell/Config_haskell.ts +35 -52
- package/project/.sdk/src/cmp/haskell/Package_haskell.ts +1 -0
- package/project/.sdk/src/cmp/haskell/Test_haskell.ts +1 -1
- package/project/.sdk/src/cmp/haskell/utility_haskell.ts +15 -5
- package/project/.sdk/src/cmp/java/Config_java.ts +21 -0
- package/project/.sdk/src/cmp/kotlin/Config_kotlin.ts +15 -0
- package/project/.sdk/src/cmp/ocaml/Config_ocaml.ts +42 -39
- package/project/.sdk/src/cmp/perl/Config_perl.ts +15 -0
- package/project/.sdk/src/cmp/perl/fragment/Main.fragment.pm +3 -1
- package/project/.sdk/src/cmp/rust/Config_rust.ts +44 -0
- package/project/.sdk/src/cmp/rust/fragment/Main.fragment.rs +4 -2
- package/project/.sdk/src/cmp/scala/Config_scala.ts +15 -0
- package/project/.sdk/src/cmp/swift/Config_swift.ts +17 -0
- package/project/.sdk/src/cmp/swift/fragment/Main.fragment.swift +3 -1
- package/project/.sdk/src/cmp/zig/Config_zig.ts +44 -0
- package/project/.sdk/src/cmp/zig/TestEntity_zig.ts +9 -2
- package/project/.sdk/src/cmp/zig/fragment/Main.fragment.zig +3 -1
- package/project/.sdk/tm/c/core/sdk.h +1 -0
- package/project/.sdk/tm/c/utility/make_options.c +5 -1
- package/project/.sdk/tm/clojure/src/sdk/core.clj +51 -3
- package/project/.sdk/tm/cpp/core/types.hpp +4 -1
- package/project/.sdk/tm/cpp/utility/pipeline.hpp +5 -1
- package/project/.sdk/tm/csharp/test/PipelineTest.cs +15 -0
- package/project/.sdk/tm/csharp/utility/MakeOptions.cs +67 -1
- package/project/.sdk/tm/dart/lib/utility/MakeOptionsUtility.dart +43 -0
- package/project/.sdk/tm/elixir/lib/projectname/utility.ex +58 -2
- package/project/.sdk/tm/haskell/{test/TestJson.hs → src/SdkJson.hs} +8 -4
- package/project/.sdk/tm/haskell/src/SdkRuntime.hs +55 -2
- package/project/.sdk/tm/haskell/test/Runner.hs +1 -1
- package/project/.sdk/tm/haskell/test/StructCorpus.hs +1 -1
- package/project/.sdk/tm/java/core/SdkClient.java +3 -1
- package/project/.sdk/tm/java/utility/MakeOptions.java +5 -1
- package/project/.sdk/tm/kotlin/core/SdkClient.kt +3 -1
- package/project/.sdk/tm/kotlin/utility/MakeOptions.kt +5 -1
- package/project/.sdk/tm/ocaml/Makefile +3 -2
- package/project/.sdk/tm/ocaml/sdk_json.ml +106 -0
- package/project/.sdk/tm/ocaml/sdk_runtime.ml +56 -0
- package/project/.sdk/tm/ocaml/test/struct_corpus.ml +4 -86
- package/project/.sdk/tm/perl/utility/make_options.pm +5 -1
- package/project/.sdk/tm/rust/utility/make_options.rs +79 -1
- package/project/.sdk/tm/scala/core/SdkClient.scala +3 -1
- package/project/.sdk/tm/scala/utility/Make.scala +5 -1
- package/project/.sdk/tm/swift/Sources/ProjectNameSDK/utility/MakeOptions.swift +5 -1
- package/project/.sdk/tm/zig/core/utility.zig +85 -1
- package/project/sdkgen-package.json +57 -0
- package/src/action/action.ts +136 -6
- package/src/action/check.ts +495 -0
- package/src/action/dispatch.ts +105 -0
- package/src/action/docs.ts +310 -0
- package/src/action/doctor.ts +692 -81
- package/src/action/feature.ts +109 -17
- package/src/action/kind.ts +375 -0
- package/src/action/package.ts +1173 -0
- package/src/action/resolve.ts +362 -0
- package/src/action/target.ts +290 -108
- package/src/cmp/Docs.ts +125 -0
- package/src/cmp/ExternalDocs.ts +54 -0
- package/src/helpers/definition.ts +82 -0
- package/src/helpers/featureSource.ts +83 -13
- package/src/helpers/junk.ts +168 -0
- package/src/helpers/manifest.ts +474 -0
- package/src/helpers/modelcheck.ts +262 -0
- package/src/helpers/semver.ts +211 -0
- package/src/helpers/shipped.ts +41 -0
- package/src/helpers/stdrep.ts +70 -0
- package/src/sdkgen.ts +294 -66
- package/src/types.ts +33 -3
- package/src/utility.ts +17 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
// Where a `<kind> add <ref>` gets its definition from.
|
|
2
|
+
//
|
|
3
|
+
// One resolver for every KIND of thing an add can install — targets today,
|
|
4
|
+
// features as of this change, more later — because the ref grammar is the
|
|
5
|
+
// same whatever is being added, and it had drifted: `target add` accepted a
|
|
6
|
+
// path ref and an alias, while `feature add` accepted only a bare name and
|
|
7
|
+
// read from a hardcoded `node_modules/@voxgig/sdkgen`. A feature defined
|
|
8
|
+
// anywhere else could not be added at all.
|
|
9
|
+
//
|
|
10
|
+
// It lives in its own module rather than in `target.ts` because `target.ts`
|
|
11
|
+
// imports `feature_add`, so a resolver there would put `feature.ts` and
|
|
12
|
+
// `target.ts` in a require cycle.
|
|
13
|
+
|
|
14
|
+
import Path from 'node:path'
|
|
15
|
+
|
|
16
|
+
import { getelem } from '@voxgig/struct'
|
|
17
|
+
|
|
18
|
+
import { KIT } from '../types'
|
|
19
|
+
|
|
20
|
+
import { definitionPath } from '../helpers/definition'
|
|
21
|
+
import { readManifest, checkShape, ITEM_NAME_RE } from '../helpers/manifest'
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
// The bundled scaffold: what a bare name resolves to.
|
|
25
|
+
const BUNDLED = 'node_modules/@voxgig/sdkgen/project/.sdk'
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
type Source = {
|
|
29
|
+
// The name it is INSTALLED as (the alias, when one was given).
|
|
30
|
+
name: string
|
|
31
|
+
|
|
32
|
+
// The name it has in the SOURCE. Differs from `name` only for an alias.
|
|
33
|
+
origname: string
|
|
34
|
+
|
|
35
|
+
// The resolved `.sdk` folder, as a path to read from.
|
|
36
|
+
folder: string
|
|
37
|
+
|
|
38
|
+
// The same folder relative to the project, '/'-normalised — the value
|
|
39
|
+
// recorded as provenance. See helpers/stdrep.
|
|
40
|
+
base: string
|
|
41
|
+
|
|
42
|
+
// The definition file inside that folder, for this kind.
|
|
43
|
+
model: string
|
|
44
|
+
|
|
45
|
+
// The sdkgen package that provided it, when the source has a manifest.
|
|
46
|
+
// Undefined for a bare `.sdk`-shaped folder, which stays legal.
|
|
47
|
+
package?: string
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
// Last path segment of a ref. A ref may be a bare name ('go'), a
|
|
52
|
+
// package-relative path ('@acme/kit/go'), or an ABSOLUTE path — and on Windows
|
|
53
|
+
// an absolute path is separated by `\`, so splitting on '/' alone hands back
|
|
54
|
+
// the whole path as the name and every lookup below then misses. On POSIX
|
|
55
|
+
// Path.sep IS '/', so this is the same split it always was.
|
|
56
|
+
function lastSegment(ref: string): string {
|
|
57
|
+
return getelem(ref.split('/').flatMap((p: string) => p.split(Path.sep)), -1)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
function resolveSource(ref: string, kind: string, ctx$: any): Source {
|
|
62
|
+
const root = ctx$.folder
|
|
63
|
+
const fs = ctx$.fs()
|
|
64
|
+
|
|
65
|
+
let folder = Path.normalize(Path.join(root, BUNDLED))
|
|
66
|
+
let name = lastSegment(ref)
|
|
67
|
+
|
|
68
|
+
// `<ref>~<alias>` installs the ref's definition under a different name.
|
|
69
|
+
//
|
|
70
|
+
// The `~` is only an alias separator in the LAST SEGMENT, which is where a
|
|
71
|
+
// name can appear. Splitting the whole ref on it broke any ref whose PATH
|
|
72
|
+
// contains a tilde — and on Windows that is routine: an 8.3 short name like
|
|
73
|
+
// `C:\Users\RUNNER~1\AppData\Local\Temp\pkg\circuitbreaker` was read as
|
|
74
|
+
// "install `C:\Users\RUNNER` under the alias `1\AppData\...`", which then
|
|
75
|
+
// looked for `C:\Users\.sdk`. Legal on POSIX too — a directory may simply
|
|
76
|
+
// be called `foo~bar`.
|
|
77
|
+
const sep = Math.max(ref.lastIndexOf('/'), ref.lastIndexOf(Path.sep))
|
|
78
|
+
const dir = sep < 0 ? '' : ref.slice(0, sep + 1)
|
|
79
|
+
const last = sep < 0 ? ref : ref.slice(sep + 1)
|
|
80
|
+
|
|
81
|
+
const aliasing = last.split('~')
|
|
82
|
+
const origlast = aliasing[0]
|
|
83
|
+
|
|
84
|
+
let aliasref = dir + origlast
|
|
85
|
+
let origname = origlast
|
|
86
|
+
if (1 < aliasing.length) {
|
|
87
|
+
name = aliasing.slice(1).join('~')
|
|
88
|
+
|
|
89
|
+
// The alias becomes a DESTINATION: `model/<kind>/<name>.aontu`,
|
|
90
|
+
// `src/cmp/<name>/`, `tm/<name>/` — all written, and `target add`
|
|
91
|
+
// overwrites what it writes. `go~..` therefore redirects the copy out of
|
|
92
|
+
// the target-specific directory and over unrelated scaffold. Checked
|
|
93
|
+
// against the same grammar the manifest applies to a name, because it is
|
|
94
|
+
// the same thing: what the item is called once installed.
|
|
95
|
+
if (!ITEM_NAME_RE.test(name)) {
|
|
96
|
+
throw new Error(
|
|
97
|
+
'Invalid ' + kind + ' alias: ' + JSON.stringify(name) +
|
|
98
|
+
' in ' + ref + '\n an alias is a NAME (matching ' +
|
|
99
|
+
ITEM_NAME_RE.source + '), not a path — it becomes the directory the ' +
|
|
100
|
+
kind + ' is installed into')
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const search: string[] = []
|
|
105
|
+
let found = false
|
|
106
|
+
|
|
107
|
+
// Windows: an absolute ref is `D:\a\...` or `D:/a/...`, and a Path.join'd
|
|
108
|
+
// one carries backslashes, so neither `includes('/')` nor `startsWith('/')`
|
|
109
|
+
// recognises it. Path.isAbsolute and Path.sep are platform-correct and
|
|
110
|
+
// reduce to the same answers on POSIX.
|
|
111
|
+
if (aliasref.includes('/') || aliasref.includes(Path.sep)) {
|
|
112
|
+
// NOTE: the last path element of the ref is the name, not a folder.
|
|
113
|
+
const aliasbase = Path.dirname(aliasref)
|
|
114
|
+
|
|
115
|
+
if (!Path.isAbsolute(aliasref)) {
|
|
116
|
+
folder = Path.normalize(Path.join(root, 'node_modules', aliasbase, '.sdk'))
|
|
117
|
+
search.push(folder)
|
|
118
|
+
found = fs.existsSync(folder)
|
|
119
|
+
|
|
120
|
+
if (!found) {
|
|
121
|
+
folder = Path.normalize(Path.join(root, aliasbase, '.sdk'))
|
|
122
|
+
search.push(folder)
|
|
123
|
+
found = fs.existsSync(folder)
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
folder = Path.normalize(Path.join(aliasbase, '.sdk'))
|
|
128
|
+
search.push(folder)
|
|
129
|
+
found = fs.existsSync(folder)
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
search.push(folder)
|
|
134
|
+
found = fs.existsSync(folder)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (!found) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
capitalise(kind) + ' folder not found in:\n' + search.join('\n '))
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// `base` is the folder relative to the project root. Compare with the
|
|
143
|
+
// PLATFORM separator: on Windows `root + '/'` never prefixes a normalised
|
|
144
|
+
// absolute path, so the root would not be stripped and `base` would stay
|
|
145
|
+
// absolute. Normalise both sides first for the same reason.
|
|
146
|
+
const nroot = Path.normalize(root)
|
|
147
|
+
const rootslash = nroot.endsWith(Path.sep) ? nroot : nroot + Path.sep
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
name,
|
|
151
|
+
origname,
|
|
152
|
+
folder,
|
|
153
|
+
// '/'-normalised, unlike `folder`. `base` is the one value here that gets
|
|
154
|
+
// WRITTEN INTO A COMMITTED FILE (the provenance stamp), so it must not
|
|
155
|
+
// depend on the OS that ran the add: on Windows Path.join yields
|
|
156
|
+
// `node_modules\@voxgig\sdkgen\project\.sdk`, so the same project resynced
|
|
157
|
+
// on Linux and on Windows produced two different model files and each
|
|
158
|
+
// churned the other's. Forward slashes are accepted by every Node path API
|
|
159
|
+
// on Windows, so the readers are unaffected.
|
|
160
|
+
base: (folder.startsWith(rootslash)
|
|
161
|
+
? folder.slice(rootslash.length)
|
|
162
|
+
: folder).split(Path.sep).join('/'),
|
|
163
|
+
// Path.join, not concatenation: an absolute Windows ref makes `folder`
|
|
164
|
+
// backslash-separated, and appending '/model/...' produced a mixed-
|
|
165
|
+
// separator path that some readers handle and others do not.
|
|
166
|
+
model: definitionPath(folder, kind, origname),
|
|
167
|
+
|
|
168
|
+
// The package that provided it, when the source declares a manifest.
|
|
169
|
+
// Read here rather than by the callers so a DIRECT ref
|
|
170
|
+
// (`target add ../pkg/iot-go`) records the same provenance
|
|
171
|
+
// `package add @acme/sdkgen-iot` would — the two spellings install the
|
|
172
|
+
// same thing, so they must record the same thing.
|
|
173
|
+
//
|
|
174
|
+
// A manifest is OPTIONAL for a direct ref and its absence is not a
|
|
175
|
+
// finding here: a bare `.sdk`-shaped folder is still a valid source, and
|
|
176
|
+
// every consumer's existing fixtures are exactly that. It is `package
|
|
177
|
+
// add` that requires one.
|
|
178
|
+
package: sourcePackage(fs, folder, kind, origname, ctx$),
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
// The manifest's package name, or undefined.
|
|
184
|
+
//
|
|
185
|
+
// TOLERANT BY DESIGN, on this path. A malformed manifest must not break
|
|
186
|
+
// `target add` — the definition, the components and the templates are all
|
|
187
|
+
// present and correct, and refusing to install them because a JSON file
|
|
188
|
+
// beside them has a trailing comma would be a worse outcome than installing
|
|
189
|
+
// them with one provenance line missing. `package add` validates properly and
|
|
190
|
+
// refuses; this only reads a name.
|
|
191
|
+
//
|
|
192
|
+
// Tolerant is not the same as credulous. The SHAPE is checked before the name
|
|
193
|
+
// is believed, because `package:` provenance is what `package update` later
|
|
194
|
+
// acts on: recording a project as belonging to `@acme/sdkgen-iot` on the
|
|
195
|
+
// strength of a file that declares no schema version and no `provides` would
|
|
196
|
+
// point a future update at a package that cannot be added at all. A manifest
|
|
197
|
+
// that would fail validation is treated exactly like one that would not
|
|
198
|
+
// parse — warn, and record nothing.
|
|
199
|
+
function sourcePackage(
|
|
200
|
+
fs: any, folder: string, kind: string, origname: string, ctx$: any,
|
|
201
|
+
): string | undefined {
|
|
202
|
+
const read = readManifest(fs, folder)
|
|
203
|
+
|
|
204
|
+
if (null != read.err) {
|
|
205
|
+
warnManifest(ctx$, read.file, read.err)
|
|
206
|
+
return undefined
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (null == read.manifest) {
|
|
210
|
+
return undefined
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
const shape = checkShape(read.manifest, read.file)
|
|
214
|
+
|
|
215
|
+
if (0 < shape.length) {
|
|
216
|
+
warnManifest(ctx$, read.file,
|
|
217
|
+
shape.map((f: any) => f.note).join('; '))
|
|
218
|
+
return undefined
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// The manifest must actually CLAIM this item. A package may carry a
|
|
222
|
+
// definition it deliberately does not list — that is what the
|
|
223
|
+
// `manifest-item-unclaimed` warning is about, "nothing will install it" —
|
|
224
|
+
// and stamping the package name onto one anyway would record that
|
|
225
|
+
// `@acme/sdkgen-iot` supplied something `package add @acme/sdkgen-iot`
|
|
226
|
+
// would never install, which is exactly the equivalence the comment at the
|
|
227
|
+
// call site rests on. `package update` would then act on it.
|
|
228
|
+
const claimed = read.manifest.provides?.[kind]
|
|
229
|
+
|
|
230
|
+
if (!Array.isArray(claimed) || !claimed.includes(origname)) {
|
|
231
|
+
ctx$.log?.info({
|
|
232
|
+
point: 'package-item-unclaimed', file: read.file, kind, name: origname,
|
|
233
|
+
note: read.file + ': ' + kind + ' `' + origname + '` is not listed in ' +
|
|
234
|
+
'`provides.' + kind + '`, so the copy records no `package` ' +
|
|
235
|
+
'provenance — add it to the manifest if the package supplies it'
|
|
236
|
+
})
|
|
237
|
+
return undefined
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return read.manifest.name
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
function warnManifest(ctx$: any, file: string, err: string) {
|
|
245
|
+
ctx$.log?.warn({
|
|
246
|
+
point: 'package-manifest-unreadable', file, err,
|
|
247
|
+
note: file + ': ignoring an unusable package manifest (' + err +
|
|
248
|
+
'); the copy records no `package` provenance'
|
|
249
|
+
})
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
// Teach the IN-MEMORY model about items that have just been installed.
|
|
254
|
+
//
|
|
255
|
+
// An action reads `actx.model`, compiled from `model/sdk.aontu` before the
|
|
256
|
+
// run. Writing `model/target/iotgo.aontu` does not change it and nothing
|
|
257
|
+
// recompiles mid-process, so anything later in the SAME command behaves as if
|
|
258
|
+
// the item is not installed.
|
|
259
|
+
//
|
|
260
|
+
// That is not cosmetic. `feature add` copies a feature's source into every
|
|
261
|
+
// target IN THE MODEL, using the two-tree lookup that reaches a feature
|
|
262
|
+
// package's overlay — so a target missing from the model gets source only
|
|
263
|
+
// from its own tree. For a target and an active feature that come from
|
|
264
|
+
// DIFFERENT packages, that means no source at all: the overlay is never
|
|
265
|
+
// consulted for it, and the target's own tree does not have it. Silent, bar
|
|
266
|
+
// one `feature-source-missing` warning.
|
|
267
|
+
//
|
|
268
|
+
// ONE definition, called by `target_add` before its own fan-out and by
|
|
269
|
+
// `package add` after each kind, because two places computing what to record
|
|
270
|
+
// is how the recorded values drift from the stamped ones.
|
|
271
|
+
function registerInstalled(kind: string, refs: string[], ctx$: any) {
|
|
272
|
+
const kit: any = ctx$.model?.main?.[KIT]
|
|
273
|
+
|
|
274
|
+
if (null == kit) {
|
|
275
|
+
return
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const items = kit[kind] = kit[kind] ?? {}
|
|
279
|
+
|
|
280
|
+
for (const ref of refs) {
|
|
281
|
+
let source: Source
|
|
282
|
+
try {
|
|
283
|
+
source = resolveSource(ref, kind, ctx$)
|
|
284
|
+
}
|
|
285
|
+
catch (err: any) {
|
|
286
|
+
ctx$.log?.warn({
|
|
287
|
+
point: 'model-register-failed', kind, ref, err: err.message,
|
|
288
|
+
note: ref + ': could not be added to the in-memory model (' +
|
|
289
|
+
err.message + '); anything later in this command will behave as ' +
|
|
290
|
+
'if it is not installed'
|
|
291
|
+
})
|
|
292
|
+
continue
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Merge, never replace: the model may already carry the project's own
|
|
296
|
+
// configuration for this item, which is the project's, not the source's.
|
|
297
|
+
items[source.name] = {
|
|
298
|
+
...(items[source.name] ?? {}),
|
|
299
|
+
name: source.name,
|
|
300
|
+
base: source.base,
|
|
301
|
+
origname: source.origname,
|
|
302
|
+
...(null == source.package ? {} : { package: source.package }),
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
// Is this name already installed FROM SOMEWHERE ELSE?
|
|
309
|
+
//
|
|
310
|
+
// `add` is overwrite, deliberately — that is how a resync works. But
|
|
311
|
+
// overwriting one package's target with a different package's target of the
|
|
312
|
+
// same name is not a resync, it is a collision, and doing it silently
|
|
313
|
+
// replaces a working target's model, components and templates with another's.
|
|
314
|
+
//
|
|
315
|
+
// Returns the conflicting record, or undefined when the name is free or is
|
|
316
|
+
// the SAME source (which is a resync and must keep working).
|
|
317
|
+
function nameConflict(
|
|
318
|
+
kind: string, source: Source, ctx$: any,
|
|
319
|
+
): { package?: string, base?: string } | undefined {
|
|
320
|
+
const declared: any = ctx$.model?.main?.[KIT]?.[kind]?.[source.name]
|
|
321
|
+
|
|
322
|
+
if (null == declared || 'object' !== typeof declared) {
|
|
323
|
+
return undefined
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Nothing recorded — a copy predating provenance. It cannot be shown to be
|
|
327
|
+
// a different source, and refusing on a suspicion would block every
|
|
328
|
+
// pre-provenance project from adopting a package.
|
|
329
|
+
if (null == declared.base || '' === declared.base) {
|
|
330
|
+
return undefined
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const samePackage = null != source.package && '' !== source.package &&
|
|
334
|
+
declared.package === source.package
|
|
335
|
+
|
|
336
|
+
const sameBase = normaliseBase(declared.base) === normaliseBase(source.base)
|
|
337
|
+
|
|
338
|
+
return (samePackage || sameBase) ? undefined : declared
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
function normaliseBase(base: string): string {
|
|
343
|
+
return Path.normalize(String(base ?? '')).split(Path.sep).join('/')
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
function capitalise(s: string): string {
|
|
348
|
+
return s.charAt(0).toUpperCase() + s.slice(1)
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
export type {
|
|
353
|
+
Source,
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export {
|
|
357
|
+
resolveSource,
|
|
358
|
+
registerInstalled,
|
|
359
|
+
nameConflict,
|
|
360
|
+
lastSegment,
|
|
361
|
+
BUNDLED,
|
|
362
|
+
}
|