@arc-e-tect/api-only-publisher 0.7.1 → 0.8.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/README.adoc +186 -18
- package/package.json +1 -1
- package/src/aggregate.js +274 -50
- package/src/cli.js +101 -6
- package/src/closure.js +1 -1
- package/src/config-command.js +100 -0
- package/src/config.js +210 -7
- package/src/init-config.js +27 -7
- package/src/init.js +10 -4
- package/src/pipeline.js +26 -12
- package/src/split.js +1 -1
package/src/init.js
CHANGED
|
@@ -322,17 +322,19 @@ const CONFIG_FILE = "apionly.yaml";
|
|
|
322
322
|
* completion is measured against; without it, apionly.yaml is compared as every
|
|
323
323
|
* other file is.
|
|
324
324
|
*
|
|
325
|
+
* @param {{paths: string, location: string}} [portfolio] the portfolio section to
|
|
326
|
+
* add when apionly.yaml lacks one; see addMissingConfig for what it does with it
|
|
325
327
|
* @returns {{rel: string, status: "missing"|"identical"|"differs", added?: string[], text?: string}[]}
|
|
326
328
|
* `added` and `text` -- the completed content -- are there only for apionly.yaml,
|
|
327
329
|
* and only when something was missing from it.
|
|
328
330
|
*/
|
|
329
|
-
function plan(targetDir, files, values) {
|
|
331
|
+
function plan(targetDir, files, values, portfolio) {
|
|
330
332
|
return Object.entries(files).map(([rel, content]) => {
|
|
331
333
|
const file = path.join(targetDir, rel);
|
|
332
334
|
if (!fs.existsSync(file)) return { rel, status: "missing" };
|
|
333
335
|
const onDisk = fs.readFileSync(file, "utf8");
|
|
334
336
|
if (rel === CONFIG_FILE && values) {
|
|
335
|
-
const completed = addMissingConfig(onDisk, { ...DEFAULTS, ...values });
|
|
337
|
+
const completed = addMissingConfig(onDisk, { ...DEFAULTS, ...values }, portfolio);
|
|
336
338
|
if (completed.added.length > 0) {
|
|
337
339
|
const status = normalised(completed.text) === normalised(content) ? "identical" : "differs";
|
|
338
340
|
return { rel, status, added: completed.added, text: completed.text };
|
|
@@ -356,13 +358,17 @@ function plan(targetDir, files, values) {
|
|
|
356
358
|
* comment already there exactly as it was. A kind already declared, however it
|
|
357
359
|
* reads, is never touched -- what is already there is not changed, only what is
|
|
358
360
|
* not there is added.
|
|
361
|
+
*
|
|
362
|
+
* `portfolio`, given, is added the same way, as one more slot: whether the
|
|
363
|
+
* library is about to have more than one target -- and so whether this is worth
|
|
364
|
+
* asking about at all -- is decided before init is called, not here.
|
|
359
365
|
*/
|
|
360
|
-
function init(targetDir, { values = DEFAULTS, force = false, log = () => {} } = {}) {
|
|
366
|
+
function init(targetDir, { values = DEFAULTS, force = false, log = () => {}, portfolio = null } = {}) {
|
|
361
367
|
const files = scaffold(values);
|
|
362
368
|
const report = { created: [], overwritten: [], identical: [], differing: [], updated: [] };
|
|
363
369
|
const updates = [];
|
|
364
370
|
|
|
365
|
-
for (const { rel, status, added, text } of plan(targetDir, files, values)) {
|
|
371
|
+
for (const { rel, status, added, text } of plan(targetDir, files, values, portfolio)) {
|
|
366
372
|
if (added && !force) {
|
|
367
373
|
fs.writeFileSync(path.join(targetDir, rel), text);
|
|
368
374
|
report.updated.push(rel);
|
package/src/pipeline.js
CHANGED
|
@@ -9,7 +9,7 @@ const YAML = require("yaml");
|
|
|
9
9
|
|
|
10
10
|
const { substituteFile } = require("./placeholders");
|
|
11
11
|
const { stampFile } = require("./version");
|
|
12
|
-
const { generateAsyncApi, isAggregate } = require("./aggregate");
|
|
12
|
+
const { generateAsyncApi, generateOpenApi, openapiPushDown, isAggregate } = require("./aggregate");
|
|
13
13
|
const { stampFiles, componentPaths, strayPaths, fragmentStamps, unresolvedStamps, FragmentPathError, KEY } = require("./fragment-paths");
|
|
14
14
|
|
|
15
15
|
class BuildError extends Error {}
|
|
@@ -85,7 +85,7 @@ function substituteTree(config, kind, log) {
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
function bundle(config, target, kind, outFile, log, { stagingRoot } = {}) {
|
|
88
|
-
const source = config.
|
|
88
|
+
const source = config.bundleRootPath(target, kind, stagingRoot);
|
|
89
89
|
if (!fs.existsSync(source)) {
|
|
90
90
|
throw new BuildError(`target '${target}': bundle root not found at ${source}`);
|
|
91
91
|
}
|
|
@@ -130,7 +130,7 @@ function bundleWithFragmentPaths(config, target, kind, outFile, log) {
|
|
|
130
130
|
return YAML.parse(fs.readFileSync(file, "utf8"));
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
-
log(`-- Bundling ${path.basename(config.
|
|
133
|
+
log(`-- Bundling ${path.basename(config.bundleRootPath(target, kind))} with ${KEY}`);
|
|
134
134
|
const discovered = componentPaths(pass("discover", null));
|
|
135
135
|
const fragments = new Set([...discovered.values()].filter(Boolean));
|
|
136
136
|
const document = pass("stamp", fragments);
|
|
@@ -169,7 +169,7 @@ function bundleInlinedWithFragmentPaths(config, target, kind, outFile, log) {
|
|
|
169
169
|
const root = path.join(scratch, "stamp");
|
|
170
170
|
fs.cpSync(config.stagingRoot(kind), root, { recursive: true });
|
|
171
171
|
|
|
172
|
-
const bundleRoot = path.relative(root, config.
|
|
172
|
+
const bundleRoot = path.relative(root, config.bundleRootPath(target, kind, root)).split(path.sep).join("/");
|
|
173
173
|
try {
|
|
174
174
|
stampFiles(root, { except: new Set([bundleRoot]) });
|
|
175
175
|
} catch (error) {
|
|
@@ -177,7 +177,7 @@ function bundleInlinedWithFragmentPaths(config, target, kind, outFile, log) {
|
|
|
177
177
|
throw error;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
log(`-- Bundling ${path.basename(config.
|
|
180
|
+
log(`-- Bundling ${path.basename(config.bundleRootPath(target, kind))} with ${KEY}`);
|
|
181
181
|
const file = path.join(scratch, "stamp.yaml");
|
|
182
182
|
bundle(config, target, kind, file, () => {}, { stagingRoot: root });
|
|
183
183
|
const document = YAML.parse(fs.readFileSync(file, "utf8"));
|
|
@@ -240,8 +240,11 @@ function prepare(config, { kinds = ["openapi", "asyncapi"], log = () => {} } = {
|
|
|
240
240
|
stage(config, kind, log);
|
|
241
241
|
substituteTree(config, kind, log);
|
|
242
242
|
for (const target of targets) {
|
|
243
|
-
if (isAggregate(config, target, kind)
|
|
243
|
+
if (!isAggregate(config, target, kind)) continue;
|
|
244
|
+
if (kind === "asyncapi") {
|
|
244
245
|
generateAsyncApi(config, target, { log });
|
|
246
|
+
} else {
|
|
247
|
+
generateOpenApi(config, target, { log });
|
|
245
248
|
}
|
|
246
249
|
}
|
|
247
250
|
}
|
|
@@ -269,14 +272,13 @@ function build(config, { targets, versionOf = () => null, kinds = ["openapi", "a
|
|
|
269
272
|
log(`\n=== ${target} (${kind}) ===`);
|
|
270
273
|
// An aggregate has no hand-written bundle root; it is synthesised from
|
|
271
274
|
// its members into the staged tree, so it can never fall behind them.
|
|
275
|
+
let openapiOwners = null;
|
|
272
276
|
if (isAggregate(config, target, kind)) {
|
|
273
|
-
if (kind
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
);
|
|
277
|
+
if (kind === "asyncapi") {
|
|
278
|
+
generateAsyncApi(config, target, { log });
|
|
279
|
+
} else {
|
|
280
|
+
openapiOwners = generateOpenApi(config, target, { log }).owners;
|
|
278
281
|
}
|
|
279
|
-
generateAsyncApi(config, target, { log });
|
|
280
282
|
}
|
|
281
283
|
const outFile = path.join(config.distDir(target), config.outputName(kind));
|
|
282
284
|
if (config.fragmentPaths(kind)) {
|
|
@@ -284,6 +286,18 @@ function build(config, { targets, versionOf = () => null, kinds = ["openapi", "a
|
|
|
284
286
|
} else {
|
|
285
287
|
bundle(config, target, kind, outFile, log);
|
|
286
288
|
}
|
|
289
|
+
if (openapiOwners) {
|
|
290
|
+
// Pass 2: only once bundling has resolved every $ref does an
|
|
291
|
+
// operation's id, or whether it already sets its own security,
|
|
292
|
+
// become visible at all.
|
|
293
|
+
const { text, reconciled } = openapiPushDown(fs.readFileSync(outFile, "utf8"), openapiOwners, {
|
|
294
|
+
operationIdStrategy: config.portfolioOperationIdStrategy(),
|
|
295
|
+
});
|
|
296
|
+
fs.writeFileSync(outFile, text);
|
|
297
|
+
for (const r of reconciled) {
|
|
298
|
+
log(`-- Reconciled tag '${r.key}': two members describe it differently; kept the first's`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
287
301
|
const version = versionOf(target);
|
|
288
302
|
if (version) {
|
|
289
303
|
log(`-- Stamping version '${version}'`);
|
package/src/split.js
CHANGED
|
@@ -111,7 +111,7 @@ function split(config, { by = "kind", outDir, log = () => {} } = {}) {
|
|
|
111
111
|
// Union of every member's closure.
|
|
112
112
|
const files = new Set();
|
|
113
113
|
for (const { target, kind } of members) {
|
|
114
|
-
const entry = config.
|
|
114
|
+
const entry = config.bundleRootPath(target, kind);
|
|
115
115
|
if (!fs.existsSync(entry)) {
|
|
116
116
|
throw new SplitError(
|
|
117
117
|
`target '${target}': ${kind} bundle root not found at ${entry}; build first so the tree is staged`
|