bdy 1.24.8 → 1.25.0-dev
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/distTs/detect-rules.json +351 -0
- package/distTs/package.json +7 -2
- package/distTs/src/cliIndex.js +2 -0
- package/distTs/src/command/yaml/actions/detect.js +268 -0
- package/distTs/src/command/yaml/actions/info.js +79 -0
- package/distTs/src/command/yaml/actions/list.js +96 -0
- package/distTs/src/command/yaml/actions/schema.js +104 -0
- package/distTs/src/command/yaml/actions.js +16 -0
- package/distTs/src/command/yaml/cache.js +106 -0
- package/distTs/src/command/yaml/pipeline.js +53 -0
- package/distTs/src/command/yaml/render.js +111 -0
- package/distTs/src/command/yaml/schemaUtils.js +164 -0
- package/distTs/src/command/yaml/validate.js +300 -0
- package/distTs/src/command/yaml.js +20 -0
- package/distTs/src/diskCache.js +200 -0
- package/distTs/src/openapi.js +10 -81
- package/distTs/src/texts.js +66 -1
- package/distTs/src/utils.js +18 -13
- package/package.json +7 -2
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const utils_1 = require("../../../utils");
|
|
7
|
+
const output_1 = __importDefault(require("../../../output"));
|
|
8
|
+
const texts_1 = require("../../../texts");
|
|
9
|
+
const schema_1 = require("./schema");
|
|
10
|
+
const schemaUtils_1 = require("../schemaUtils");
|
|
11
|
+
const detect_1 = require("./detect");
|
|
12
|
+
const render_1 = require("../render");
|
|
13
|
+
const commandYamlActionsInfo = (0, utils_1.newCommand)('info', texts_1.DESC_COMMAND_YAML_ACTIONS_INFO);
|
|
14
|
+
commandYamlActionsInfo.argument('<type>', texts_1.OPTION_ACTION_TYPE);
|
|
15
|
+
commandYamlActionsInfo.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
16
|
+
commandYamlActionsInfo.addHelpText('after', `\nEXAMPLES:${texts_1.EXAMPLE_YAML_ACTIONS_INFO}`);
|
|
17
|
+
commandYamlActionsInfo.action(async (type, options) => {
|
|
18
|
+
await (0, schemaUtils_1.ensureYamlSchema)();
|
|
19
|
+
const actions = (0, schema_1.loadSchema)();
|
|
20
|
+
const action = (0, schema_1.findAction)(actions, type);
|
|
21
|
+
if (!action) {
|
|
22
|
+
if (options.format === 'json') {
|
|
23
|
+
output_1.default.json(null);
|
|
24
|
+
output_1.default.exitNormal();
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
output_1.default.error((0, texts_1.ERR_ACTION_NOT_FOUND)(type));
|
|
28
|
+
const suggestions = (0, schema_1.suggestActions)(actions, type);
|
|
29
|
+
if (suggestions.length > 0) {
|
|
30
|
+
output_1.default.muted((0, texts_1.TXT_ACTION_DID_YOU_MEAN)(suggestions.map((a) => `${a.type} (${a.name})`).join(', ')));
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
const detectedTypes = (0, detect_1.detectActions)(process.cwd());
|
|
34
|
+
if (detectedTypes.size > 0) {
|
|
35
|
+
const detected = actions.filter((a) => detectedTypes.has(a.type)).slice(0, 5);
|
|
36
|
+
output_1.default.muted((0, texts_1.TXT_ACTION_SUGGESTED_FROM_REPO)(detected.map((a) => `${a.type} (${a.name})`).join(', ')));
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
output_1.default.muted(texts_1.TXT_ACTION_USE_LIST);
|
|
40
|
+
output_1.default.exitNormal();
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const { common, specific } = (0, schema_1.splitProperties)(action);
|
|
44
|
+
if (options.format === 'json') {
|
|
45
|
+
output_1.default.json({
|
|
46
|
+
type: action.type,
|
|
47
|
+
slug: action.slug,
|
|
48
|
+
name: action.name,
|
|
49
|
+
description: action.description,
|
|
50
|
+
required: action.required,
|
|
51
|
+
fields: {
|
|
52
|
+
specific: (0, render_1.propertiesJson)(specific, action.required),
|
|
53
|
+
common: (0, render_1.propertiesJson)(common, action.required),
|
|
54
|
+
},
|
|
55
|
+
examples: action.examples,
|
|
56
|
+
});
|
|
57
|
+
output_1.default.exitNormal();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
output_1.default.blue(action.name, false);
|
|
61
|
+
output_1.default.gray(` · ${action.type}`);
|
|
62
|
+
output_1.default.gray(action.description);
|
|
63
|
+
output_1.default.normal('');
|
|
64
|
+
if (Object.keys(specific).length > 0) {
|
|
65
|
+
output_1.default.blue('Type-specific fields');
|
|
66
|
+
(0, render_1.outputProperties)(specific, action.required);
|
|
67
|
+
output_1.default.normal('');
|
|
68
|
+
}
|
|
69
|
+
if (Object.keys(common).length > 0) {
|
|
70
|
+
output_1.default.blue('Common fields');
|
|
71
|
+
(0, render_1.outputProperties)(common, action.required);
|
|
72
|
+
}
|
|
73
|
+
if (action.examples.length > 0) {
|
|
74
|
+
output_1.default.normal('');
|
|
75
|
+
(0, render_1.outputExamples)(action.examples);
|
|
76
|
+
}
|
|
77
|
+
output_1.default.exitNormal();
|
|
78
|
+
});
|
|
79
|
+
exports.default = commandYamlActionsInfo;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const utils_1 = require("../../../utils");
|
|
7
|
+
const output_1 = __importDefault(require("../../../output"));
|
|
8
|
+
const texts_1 = require("../../../texts");
|
|
9
|
+
const schema_1 = require("./schema");
|
|
10
|
+
const schemaUtils_1 = require("../schemaUtils");
|
|
11
|
+
const detect_1 = require("./detect");
|
|
12
|
+
function actionTable(actions) {
|
|
13
|
+
const data = [['TYPE', 'NAME', 'DESCRIPTION']];
|
|
14
|
+
for (const action of actions) {
|
|
15
|
+
const desc = action.description.length > 80
|
|
16
|
+
? action.description.substring(0, 77) + '...'
|
|
17
|
+
: action.description;
|
|
18
|
+
data.push([action.type, action.name, desc]);
|
|
19
|
+
}
|
|
20
|
+
return data;
|
|
21
|
+
}
|
|
22
|
+
function actionJson(actions, detectedTypes) {
|
|
23
|
+
return actions.map((action) => ({
|
|
24
|
+
type: action.type,
|
|
25
|
+
slug: action.slug,
|
|
26
|
+
name: action.name,
|
|
27
|
+
description: action.description,
|
|
28
|
+
suggested: detectedTypes.has(action.type),
|
|
29
|
+
}));
|
|
30
|
+
}
|
|
31
|
+
const commandYamlActionsList = (0, utils_1.newCommand)('list', texts_1.DESC_COMMAND_YAML_ACTIONS_LIST);
|
|
32
|
+
commandYamlActionsList.alias('ls');
|
|
33
|
+
commandYamlActionsList.option('-s, --search <query>', texts_1.OPTION_ACTION_SEARCH);
|
|
34
|
+
commandYamlActionsList.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
35
|
+
commandYamlActionsList.addHelpText('after', `\nEXAMPLES:${texts_1.EXAMPLE_YAML_ACTIONS_LIST}`);
|
|
36
|
+
commandYamlActionsList.action(async (options) => {
|
|
37
|
+
await (0, schemaUtils_1.ensureYamlSchema)();
|
|
38
|
+
const actions = (0, schema_1.loadSchema)();
|
|
39
|
+
const detectedTypes = (0, detect_1.detectActions)(process.cwd());
|
|
40
|
+
if (options.search) {
|
|
41
|
+
const index = (0, schema_1.createActionIndex)(actions);
|
|
42
|
+
const hits = index.search(options.search);
|
|
43
|
+
const slugSet = new Set(hits.map((h) => h.id));
|
|
44
|
+
const results = actions.filter((a) => slugSet.has(a.slug));
|
|
45
|
+
results.sort((a, b) => {
|
|
46
|
+
const ai = hits.findIndex((h) => h.id === a.slug);
|
|
47
|
+
const bi = hits.findIndex((h) => h.id === b.slug);
|
|
48
|
+
return ai - bi;
|
|
49
|
+
});
|
|
50
|
+
if (results.length === 0) {
|
|
51
|
+
if (options.format === 'json') {
|
|
52
|
+
output_1.default.json([]);
|
|
53
|
+
output_1.default.exitNormal();
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const suggestions = index.autoSuggest(options.search);
|
|
57
|
+
output_1.default.error((0, texts_1.ERR_ACTION_SEARCH_NO_RESULTS)(options.search));
|
|
58
|
+
if (suggestions.length > 0) {
|
|
59
|
+
output_1.default.muted((0, texts_1.TXT_ACTION_DID_YOU_MEAN)(suggestions.map((s) => s.suggestion).join(', ')));
|
|
60
|
+
}
|
|
61
|
+
if (detectedTypes.size > 0) {
|
|
62
|
+
const detected = actions.filter((a) => detectedTypes.has(a.type));
|
|
63
|
+
output_1.default.normal('');
|
|
64
|
+
output_1.default.blue('Suggested based on your repo');
|
|
65
|
+
output_1.default.table(actionTable(detected));
|
|
66
|
+
}
|
|
67
|
+
output_1.default.muted(texts_1.TXT_ACTION_USE_LIST);
|
|
68
|
+
output_1.default.exitNormal();
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
if (options.format === 'json') {
|
|
72
|
+
output_1.default.json(actionJson(results, detectedTypes));
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
output_1.default.table(actionTable(results));
|
|
76
|
+
}
|
|
77
|
+
output_1.default.exitNormal();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const byType = (a, b) => a.type.localeCompare(b.type);
|
|
81
|
+
if (options.format === 'json') {
|
|
82
|
+
output_1.default.json(actionJson([...actions].sort(byType), detectedTypes));
|
|
83
|
+
output_1.default.exitNormal();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
if (detectedTypes.size > 0) {
|
|
87
|
+
const detected = actions.filter((a) => detectedTypes.has(a.type)).sort(byType);
|
|
88
|
+
output_1.default.blue('Suggested');
|
|
89
|
+
output_1.default.table(actionTable(detected));
|
|
90
|
+
output_1.default.normal('');
|
|
91
|
+
}
|
|
92
|
+
output_1.default.blue(`All actions (${actions.length})`);
|
|
93
|
+
output_1.default.table(actionTable([...actions].sort(byType)));
|
|
94
|
+
output_1.default.exitNormal();
|
|
95
|
+
});
|
|
96
|
+
exports.default = commandYamlActionsList;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.loadSchema = loadSchema;
|
|
4
|
+
exports.getCommonFields = getCommonFields;
|
|
5
|
+
exports.splitProperties = splitProperties;
|
|
6
|
+
exports.findAction = findAction;
|
|
7
|
+
exports.createActionIndex = createActionIndex;
|
|
8
|
+
exports.suggestActions = suggestActions;
|
|
9
|
+
const schemaUtils_1 = require("../schemaUtils");
|
|
10
|
+
let memCached = null;
|
|
11
|
+
function deriveSlug(defKey) {
|
|
12
|
+
const base = defKey.replace(/ActionYaml$/, '');
|
|
13
|
+
return base
|
|
14
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
15
|
+
.replace(/([A-Z]+)([A-Z][a-z])/g, '$1-$2')
|
|
16
|
+
.toLowerCase();
|
|
17
|
+
}
|
|
18
|
+
function parseSchema(raw) {
|
|
19
|
+
const defs = raw.$defs || {};
|
|
20
|
+
const actionKeys = Object.keys(defs).filter((k) => k.endsWith('ActionYaml') && defs[k].deprecated !== true);
|
|
21
|
+
const sharedDefs = (0, schemaUtils_1.getSharedDefs)();
|
|
22
|
+
return actionKeys.map((key) => {
|
|
23
|
+
const def = defs[key];
|
|
24
|
+
const typeConst = def.properties?.type?.const || def.properties?.type?.enum?.[0] || '';
|
|
25
|
+
const properties = def.properties ? (0, schemaUtils_1.resolveRefs)(def.properties, sharedDefs) : {};
|
|
26
|
+
return {
|
|
27
|
+
key,
|
|
28
|
+
slug: deriveSlug(key),
|
|
29
|
+
name: def['x-name'] || def.title || key,
|
|
30
|
+
type: typeConst,
|
|
31
|
+
description: def.description || '',
|
|
32
|
+
properties,
|
|
33
|
+
required: def.required || [],
|
|
34
|
+
examples: def.examples || [],
|
|
35
|
+
tags: [...new Set([
|
|
36
|
+
...(def['x-tags'] || []),
|
|
37
|
+
...((def['x-subtypes'] || []).flatMap((s) => s['x-tags'] || [])),
|
|
38
|
+
])],
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
function loadSchema() {
|
|
43
|
+
if (memCached)
|
|
44
|
+
return memCached;
|
|
45
|
+
const raw = (0, schemaUtils_1.loadRawSchema)();
|
|
46
|
+
memCached = parseSchema(raw);
|
|
47
|
+
return memCached;
|
|
48
|
+
}
|
|
49
|
+
let commonCached = null;
|
|
50
|
+
// Fields common to every action = intersection of property keys across all actions.
|
|
51
|
+
function getCommonFields() {
|
|
52
|
+
if (commonCached)
|
|
53
|
+
return commonCached;
|
|
54
|
+
const actions = loadSchema();
|
|
55
|
+
let common = null;
|
|
56
|
+
for (const action of actions) {
|
|
57
|
+
const keys = Object.keys(action.properties);
|
|
58
|
+
if (common === null) {
|
|
59
|
+
common = new Set(keys);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
common = new Set(keys.filter((k) => common.has(k)));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
commonCached = common || new Set();
|
|
66
|
+
return commonCached;
|
|
67
|
+
}
|
|
68
|
+
function splitProperties(action) {
|
|
69
|
+
const commonFields = getCommonFields();
|
|
70
|
+
const common = {};
|
|
71
|
+
const specific = {};
|
|
72
|
+
for (const [key, prop] of Object.entries(action.properties)) {
|
|
73
|
+
if (commonFields.has(key))
|
|
74
|
+
common[key] = prop;
|
|
75
|
+
else
|
|
76
|
+
specific[key] = prop;
|
|
77
|
+
}
|
|
78
|
+
return { common, specific };
|
|
79
|
+
}
|
|
80
|
+
function findAction(actions, query) {
|
|
81
|
+
const q = query.toLowerCase();
|
|
82
|
+
return (actions.find((a) => a.slug === q) ||
|
|
83
|
+
actions.find((a) => a.type.toLowerCase() === q));
|
|
84
|
+
}
|
|
85
|
+
function createActionIndex(actions) {
|
|
86
|
+
const MiniSearch = require('minisearch');
|
|
87
|
+
const index = new MiniSearch({
|
|
88
|
+
fields: ['name', 'type', 'description', 'tags'],
|
|
89
|
+
storeFields: ['slug'],
|
|
90
|
+
searchOptions: {
|
|
91
|
+
boost: { name: 3, type: 2, tags: 2, description: 1 },
|
|
92
|
+
prefix: true,
|
|
93
|
+
fuzzy: 0.3,
|
|
94
|
+
combineWith: 'OR',
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
index.addAll(actions.map((a) => ({ id: a.slug, name: a.name, type: a.type, description: a.description, tags: a.tags.join(' '), slug: a.slug })));
|
|
98
|
+
return index;
|
|
99
|
+
}
|
|
100
|
+
function suggestActions(actions, query, limit = 5) {
|
|
101
|
+
const hits = createActionIndex(actions).search(query).slice(0, limit);
|
|
102
|
+
const bySlug = new Map(actions.map((a) => [a.slug, a]));
|
|
103
|
+
return hits.map((h) => bySlug.get(h.id)).filter(Boolean);
|
|
104
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const utils_1 = require("../../utils");
|
|
7
|
+
const texts_1 = require("../../texts");
|
|
8
|
+
const list_1 = __importDefault(require("./actions/list"));
|
|
9
|
+
const info_1 = __importDefault(require("./actions/info"));
|
|
10
|
+
const commandYamlActions = (0, utils_1.newCommand)('actions', texts_1.DESC_COMMAND_YAML_ACTIONS);
|
|
11
|
+
commandYamlActions.addCommand(list_1.default);
|
|
12
|
+
commandYamlActions.addCommand(info_1.default);
|
|
13
|
+
commandYamlActions.addHelpText('after', `
|
|
14
|
+
EXAMPLES:${texts_1.EXAMPLE_YAML_ACTIONS_LIST}
|
|
15
|
+
${texts_1.EXAMPLE_YAML_ACTIONS_INFO}`);
|
|
16
|
+
exports.default = commandYamlActions;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getCache = getCache;
|
|
7
|
+
exports.setCache = setCache;
|
|
8
|
+
exports.fingerprintFiles = fingerprintFiles;
|
|
9
|
+
exports.pruneCache = pruneCache;
|
|
10
|
+
const fs_1 = require("fs");
|
|
11
|
+
const crypto_1 = require("crypto");
|
|
12
|
+
const path_1 = __importDefault(require("path"));
|
|
13
|
+
const diskCache_1 = require("../../diskCache");
|
|
14
|
+
const DEFAULT_TTL_MS = 24 * 60 * 60 * 1000; // 24h
|
|
15
|
+
const MAX_ENTRIES = 100;
|
|
16
|
+
function cacheFilePath(key) {
|
|
17
|
+
return path_1.default.join((0, diskCache_1.cacheRoot)(), `${(0, diskCache_1.hashKey)(key)}.json`);
|
|
18
|
+
}
|
|
19
|
+
function readEntry(key) {
|
|
20
|
+
try {
|
|
21
|
+
return JSON.parse((0, diskCache_1.readCached)(cacheFilePath(key)) ?? '');
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function writeEntry(key, entry) {
|
|
28
|
+
(0, diskCache_1.writeCache)(cacheFilePath(key), JSON.stringify(entry));
|
|
29
|
+
}
|
|
30
|
+
function removeEntry(filePath) {
|
|
31
|
+
try {
|
|
32
|
+
(0, fs_1.unlinkSync)(filePath);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// ignore
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function getCache(key, fingerprint) {
|
|
39
|
+
const entry = readEntry(key);
|
|
40
|
+
if (!entry)
|
|
41
|
+
return null;
|
|
42
|
+
if (entry.fingerprint !== fingerprint)
|
|
43
|
+
return null;
|
|
44
|
+
if (Date.now() - entry.createdAt > entry.ttl)
|
|
45
|
+
return null;
|
|
46
|
+
return entry.data;
|
|
47
|
+
}
|
|
48
|
+
function setCache(key, fingerprint, data, ttl = DEFAULT_TTL_MS) {
|
|
49
|
+
writeEntry(key, { data, fingerprint, createdAt: Date.now(), ttl });
|
|
50
|
+
}
|
|
51
|
+
function fingerprintFiles(dir, filenames) {
|
|
52
|
+
const hash = (0, crypto_1.createHash)('sha256');
|
|
53
|
+
hash.update(dir);
|
|
54
|
+
for (const name of filenames) {
|
|
55
|
+
const filePath = path_1.default.join(dir, name);
|
|
56
|
+
try {
|
|
57
|
+
const stat = (0, fs_1.statSync)(filePath);
|
|
58
|
+
hash.update(`${name}:${stat.mtimeMs}:${stat.size}`);
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
hash.update(`${name}:0`);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return hash.digest('hex');
|
|
65
|
+
}
|
|
66
|
+
function pruneCache(maxAge = 7 * 24 * 60 * 60 * 1000) {
|
|
67
|
+
(0, diskCache_1.sweepStaleCache)();
|
|
68
|
+
const dir = (0, diskCache_1.cacheRoot)();
|
|
69
|
+
let entries;
|
|
70
|
+
try {
|
|
71
|
+
entries = (0, fs_1.readdirSync)(dir, { withFileTypes: true })
|
|
72
|
+
.filter((e) => e.isFile() && e.name.endsWith('.json'))
|
|
73
|
+
.map((e) => e.name);
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
const now = Date.now();
|
|
79
|
+
const aged = [];
|
|
80
|
+
for (const file of entries) {
|
|
81
|
+
const filePath = path_1.default.join(dir, file);
|
|
82
|
+
let entry = null;
|
|
83
|
+
try {
|
|
84
|
+
entry = JSON.parse((0, fs_1.readFileSync)(filePath, 'utf8'));
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// ignore
|
|
88
|
+
}
|
|
89
|
+
// Without the createdAt check the sort below compares against NaN.
|
|
90
|
+
if (!entry || !Number.isFinite(entry.createdAt)) {
|
|
91
|
+
removeEntry(filePath);
|
|
92
|
+
}
|
|
93
|
+
else if (now - entry.createdAt > maxAge) {
|
|
94
|
+
removeEntry(filePath);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
aged.push({ file: filePath, createdAt: entry.createdAt });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (aged.length > MAX_ENTRIES) {
|
|
101
|
+
aged.sort((a, b) => a.createdAt - b.createdAt);
|
|
102
|
+
for (let i = 0; i < aged.length - MAX_ENTRIES; i++) {
|
|
103
|
+
removeEntry(aged[i].file);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const utils_1 = require("../../utils");
|
|
7
|
+
const output_1 = __importDefault(require("../../output"));
|
|
8
|
+
const texts_1 = require("../../texts");
|
|
9
|
+
const schemaUtils_1 = require("./schemaUtils");
|
|
10
|
+
const render_1 = require("./render");
|
|
11
|
+
let cached = null;
|
|
12
|
+
function loadPipelineRoot() {
|
|
13
|
+
if (cached)
|
|
14
|
+
return cached;
|
|
15
|
+
const defs = (0, schemaUtils_1.getAllDefs)();
|
|
16
|
+
const sharedDefs = (0, schemaUtils_1.getSharedDefs)();
|
|
17
|
+
const pipelineDef = defs['PipelineYaml'];
|
|
18
|
+
if (!pipelineDef?.properties) {
|
|
19
|
+
cached = { properties: {}, required: [], examples: [] };
|
|
20
|
+
return cached;
|
|
21
|
+
}
|
|
22
|
+
cached = {
|
|
23
|
+
properties: (0, schemaUtils_1.resolveRefs)(pipelineDef.properties, sharedDefs),
|
|
24
|
+
required: pipelineDef.required || [],
|
|
25
|
+
examples: pipelineDef.examples || [],
|
|
26
|
+
};
|
|
27
|
+
return cached;
|
|
28
|
+
}
|
|
29
|
+
const commandYamlPipeline = (0, utils_1.newCommand)('pipeline', texts_1.DESC_COMMAND_YAML_PIPELINE);
|
|
30
|
+
commandYamlPipeline.option('--format <text|json>', texts_1.OPTION_FORMAT);
|
|
31
|
+
commandYamlPipeline.addHelpText('after', `\nEXAMPLES:${texts_1.EXAMPLE_YAML_PIPELINE}`);
|
|
32
|
+
commandYamlPipeline.action(async (options) => {
|
|
33
|
+
await (0, schemaUtils_1.ensureYamlSchema)();
|
|
34
|
+
const root = loadPipelineRoot();
|
|
35
|
+
if (options.format === 'json') {
|
|
36
|
+
output_1.default.json({
|
|
37
|
+
properties: (0, render_1.propertiesJson)(root.properties, root.required),
|
|
38
|
+
required: root.required,
|
|
39
|
+
examples: root.examples,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
output_1.default.blue('Pipeline properties');
|
|
44
|
+
output_1.default.normal('');
|
|
45
|
+
(0, render_1.outputProperties)(root.properties, root.required);
|
|
46
|
+
if (root.examples.length > 0) {
|
|
47
|
+
output_1.default.normal('');
|
|
48
|
+
(0, render_1.outputExamples)(root.examples);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
output_1.default.exitNormal();
|
|
52
|
+
});
|
|
53
|
+
exports.default = commandYamlPipeline;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.formatType = formatType;
|
|
7
|
+
exports.formatDescription = formatDescription;
|
|
8
|
+
exports.propertiesJson = propertiesJson;
|
|
9
|
+
exports.outputProperties = outputProperties;
|
|
10
|
+
exports.outputExamples = outputExamples;
|
|
11
|
+
const output_1 = __importDefault(require("../../output"));
|
|
12
|
+
function formatType(prop) {
|
|
13
|
+
if (prop.const)
|
|
14
|
+
return `"${prop.const}"`;
|
|
15
|
+
if (prop.enum)
|
|
16
|
+
return 'enum';
|
|
17
|
+
if (prop.type === 'array') {
|
|
18
|
+
if (prop.items?.type)
|
|
19
|
+
return `${prop.items.type}[]`;
|
|
20
|
+
if (prop.items?.title)
|
|
21
|
+
return `${prop.items.title}[]`;
|
|
22
|
+
return 'array';
|
|
23
|
+
}
|
|
24
|
+
if (prop.type === 'object' && prop.properties)
|
|
25
|
+
return 'object';
|
|
26
|
+
return prop.type || 'any';
|
|
27
|
+
}
|
|
28
|
+
function formatDescription(prop) {
|
|
29
|
+
const parts = [];
|
|
30
|
+
if (prop.description)
|
|
31
|
+
parts.push(prop.description);
|
|
32
|
+
if (prop.const)
|
|
33
|
+
parts.push(`Value: ${prop.const}`);
|
|
34
|
+
if (prop.enum)
|
|
35
|
+
parts.push(`Values: ${prop.enum.join(', ')}`);
|
|
36
|
+
if (prop.minimum !== undefined)
|
|
37
|
+
parts.push(`Min: ${prop.minimum}`);
|
|
38
|
+
if (prop.maximum !== undefined)
|
|
39
|
+
parts.push(`Max: ${prop.maximum}`);
|
|
40
|
+
return parts.join('. ');
|
|
41
|
+
}
|
|
42
|
+
function sortedKeys(properties, required) {
|
|
43
|
+
return Object.keys(properties).sort((a, b) => {
|
|
44
|
+
const aReq = required.includes(a);
|
|
45
|
+
const bReq = required.includes(b);
|
|
46
|
+
if (aReq !== bReq)
|
|
47
|
+
return aReq ? -1 : 1;
|
|
48
|
+
return a.localeCompare(b);
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
// Not the raw sub-schema: resolveRefs inlines every nested def, which is 36KB for
|
|
52
|
+
// trigger_conditions alone - a field every action carries.
|
|
53
|
+
function propertiesJson(properties, required) {
|
|
54
|
+
const out = {};
|
|
55
|
+
for (const key of sortedKeys(properties, required)) {
|
|
56
|
+
const prop = properties[key];
|
|
57
|
+
const field = {
|
|
58
|
+
type: formatType(prop),
|
|
59
|
+
required: required.includes(key),
|
|
60
|
+
};
|
|
61
|
+
if (prop.description)
|
|
62
|
+
field.description = prop.description;
|
|
63
|
+
if (prop.const !== undefined)
|
|
64
|
+
field.const = prop.const;
|
|
65
|
+
if (prop.enum)
|
|
66
|
+
field.enum = prop.enum;
|
|
67
|
+
if (prop.minimum !== undefined)
|
|
68
|
+
field.minimum = prop.minimum;
|
|
69
|
+
if (prop.maximum !== undefined)
|
|
70
|
+
field.maximum = prop.maximum;
|
|
71
|
+
out[key] = field;
|
|
72
|
+
}
|
|
73
|
+
return out;
|
|
74
|
+
}
|
|
75
|
+
function outputProperties(properties, required) {
|
|
76
|
+
const keys = sortedKeys(properties, required);
|
|
77
|
+
const data = [['FIELD', 'TYPE', 'REQUIRED', 'DESCRIPTION']];
|
|
78
|
+
for (const key of keys) {
|
|
79
|
+
const prop = properties[key];
|
|
80
|
+
const desc = formatDescription(prop);
|
|
81
|
+
const truncDesc = desc.length > 100 ? desc.substring(0, 97) + '...' : desc;
|
|
82
|
+
data.push([
|
|
83
|
+
key,
|
|
84
|
+
formatType(prop),
|
|
85
|
+
required.includes(key) ? 'yes' : '',
|
|
86
|
+
truncDesc,
|
|
87
|
+
]);
|
|
88
|
+
}
|
|
89
|
+
output_1.default.table(data);
|
|
90
|
+
}
|
|
91
|
+
function formatExampleYaml(value) {
|
|
92
|
+
try {
|
|
93
|
+
const YAML = require('yaml');
|
|
94
|
+
const parsed = YAML.parse(value);
|
|
95
|
+
if (parsed !== null && typeof parsed === 'object') {
|
|
96
|
+
return YAML.stringify(parsed, { indent: 2 }).trimEnd();
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// keep raw value on parse errors
|
|
101
|
+
}
|
|
102
|
+
return value.trimEnd();
|
|
103
|
+
}
|
|
104
|
+
function outputExamples(examples) {
|
|
105
|
+
output_1.default.blue('Examples');
|
|
106
|
+
for (const ex of examples) {
|
|
107
|
+
output_1.default.normal('');
|
|
108
|
+
output_1.default.yellow(`# ${ex.title}`);
|
|
109
|
+
output_1.default.gray(formatExampleYaml(ex.value));
|
|
110
|
+
}
|
|
111
|
+
}
|