@signstack/cli 0.1.1
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.md +458 -0
- package/bin/run.js +12 -0
- package/dist/apps/signstack-cli/schemas/asset.schema.json +220 -0
- package/dist/apps/signstack-cli/schemas/blueprint.schema.json +485 -0
- package/dist/apps/signstack-cli/schemas/jsonata-function.schema.json +185 -0
- package/dist/apps/signstack-cli/schemas/schema.schema.json +97 -0
- package/dist/apps/signstack-cli/schemas/template.schema.json +295 -0
- package/dist/apps/signstack-cli/src/commands/auth/login.d.ts +25 -0
- package/dist/apps/signstack-cli/src/commands/auth/login.js +229 -0
- package/dist/apps/signstack-cli/src/commands/auth/login.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/auth/logout.d.ts +10 -0
- package/dist/apps/signstack-cli/src/commands/auth/logout.js +59 -0
- package/dist/apps/signstack-cli/src/commands/auth/logout.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/auth/whoami.d.ts +9 -0
- package/dist/apps/signstack-cli/src/commands/auth/whoami.js +85 -0
- package/dist/apps/signstack-cli/src/commands/auth/whoami.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/generate.d.ts +51 -0
- package/dist/apps/signstack-cli/src/commands/generate.js +479 -0
- package/dist/apps/signstack-cli/src/commands/generate.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/preview.d.ts +24 -0
- package/dist/apps/signstack-cli/src/commands/preview.js +162 -0
- package/dist/apps/signstack-cli/src/commands/preview.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/pull.d.ts +28 -0
- package/dist/apps/signstack-cli/src/commands/pull.js +244 -0
- package/dist/apps/signstack-cli/src/commands/pull.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/push.d.ts +46 -0
- package/dist/apps/signstack-cli/src/commands/push.js +460 -0
- package/dist/apps/signstack-cli/src/commands/push.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/run.d.ts +22 -0
- package/dist/apps/signstack-cli/src/commands/run.js +126 -0
- package/dist/apps/signstack-cli/src/commands/run.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/test.d.ts +6 -0
- package/dist/apps/signstack-cli/src/commands/test.js +25 -0
- package/dist/apps/signstack-cli/src/commands/test.js.map +1 -0
- package/dist/apps/signstack-cli/src/commands/validate.d.ts +59 -0
- package/dist/apps/signstack-cli/src/commands/validate.js +558 -0
- package/dist/apps/signstack-cli/src/commands/validate.js.map +1 -0
- package/dist/apps/signstack-cli/src/index.d.ts +1 -0
- package/dist/apps/signstack-cli/src/index.js +2 -0
- package/dist/apps/signstack-cli/src/index.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/api-client.d.ts +77 -0
- package/dist/apps/signstack-cli/src/lib/api-client.js +269 -0
- package/dist/apps/signstack-cli/src/lib/api-client.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/base-command.d.ts +38 -0
- package/dist/apps/signstack-cli/src/lib/base-command.js +135 -0
- package/dist/apps/signstack-cli/src/lib/base-command.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/config.d.ts +47 -0
- package/dist/apps/signstack-cli/src/lib/config.js +106 -0
- package/dist/apps/signstack-cli/src/lib/config.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/entity-data-resolver.d.ts +31 -0
- package/dist/apps/signstack-cli/src/lib/entity-data-resolver.js +107 -0
- package/dist/apps/signstack-cli/src/lib/entity-data-resolver.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/local-resource-loader.d.ts +72 -0
- package/dist/apps/signstack-cli/src/lib/local-resource-loader.js +238 -0
- package/dist/apps/signstack-cli/src/lib/local-resource-loader.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/path-utils.d.ts +4 -0
- package/dist/apps/signstack-cli/src/lib/path-utils.js +7 -0
- package/dist/apps/signstack-cli/src/lib/path-utils.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/payload-builder.d.ts +127 -0
- package/dist/apps/signstack-cli/src/lib/payload-builder.js +545 -0
- package/dist/apps/signstack-cli/src/lib/payload-builder.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/preview-handler.d.ts +95 -0
- package/dist/apps/signstack-cli/src/lib/preview-handler.js +611 -0
- package/dist/apps/signstack-cli/src/lib/preview-handler.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/preview-output-formatter.d.ts +63 -0
- package/dist/apps/signstack-cli/src/lib/preview-output-formatter.js +198 -0
- package/dist/apps/signstack-cli/src/lib/preview-output-formatter.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/public-api-client.d.ts +13 -0
- package/dist/apps/signstack-cli/src/lib/public-api-client.js +39 -0
- package/dist/apps/signstack-cli/src/lib/public-api-client.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/resource-puller.d.ts +131 -0
- package/dist/apps/signstack-cli/src/lib/resource-puller.js +800 -0
- package/dist/apps/signstack-cli/src/lib/resource-puller.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/resource-pusher.d.ts +87 -0
- package/dist/apps/signstack-cli/src/lib/resource-pusher.js +361 -0
- package/dist/apps/signstack-cli/src/lib/resource-pusher.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/resource-scanner.d.ts +29 -0
- package/dist/apps/signstack-cli/src/lib/resource-scanner.js +101 -0
- package/dist/apps/signstack-cli/src/lib/resource-scanner.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/resource-validator.d.ts +44 -0
- package/dist/apps/signstack-cli/src/lib/resource-validator.js +158 -0
- package/dist/apps/signstack-cli/src/lib/resource-validator.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/run-handler.d.ts +47 -0
- package/dist/apps/signstack-cli/src/lib/run-handler.js +266 -0
- package/dist/apps/signstack-cli/src/lib/run-handler.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/safe-path.d.ts +28 -0
- package/dist/apps/signstack-cli/src/lib/safe-path.js +44 -0
- package/dist/apps/signstack-cli/src/lib/safe-path.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/scenario-file.d.ts +35 -0
- package/dist/apps/signstack-cli/src/lib/scenario-file.js +80 -0
- package/dist/apps/signstack-cli/src/lib/scenario-file.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/schema-validator.d.ts +8 -0
- package/dist/apps/signstack-cli/src/lib/schema-validator.js +39 -0
- package/dist/apps/signstack-cli/src/lib/schema-validator.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/url-validator.d.ts +17 -0
- package/dist/apps/signstack-cli/src/lib/url-validator.js +61 -0
- package/dist/apps/signstack-cli/src/lib/url-validator.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/yaml-document-parser.d.ts +25 -0
- package/dist/apps/signstack-cli/src/lib/yaml-document-parser.js +133 -0
- package/dist/apps/signstack-cli/src/lib/yaml-document-parser.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/yaml-transforms.d.ts +3 -0
- package/dist/apps/signstack-cli/src/lib/yaml-transforms.js +32 -0
- package/dist/apps/signstack-cli/src/lib/yaml-transforms.js.map +1 -0
- package/dist/apps/signstack-cli/src/lib/yaml-writer.d.ts +47 -0
- package/dist/apps/signstack-cli/src/lib/yaml-writer.js +160 -0
- package/dist/apps/signstack-cli/src/lib/yaml-writer.js.map +1 -0
- package/dist/apps/signstack-cli/src/types/auth.types.d.ts +48 -0
- package/dist/apps/signstack-cli/src/types/auth.types.js +31 -0
- package/dist/apps/signstack-cli/src/types/auth.types.js.map +1 -0
- package/dist/apps/signstack-cli/src/types/schema.types.d.ts +14 -0
- package/dist/apps/signstack-cli/src/types/schema.types.js +16 -0
- package/dist/apps/signstack-cli/src/types/schema.types.js.map +1 -0
- package/dist/apps/signstack-cli/src/types/yaml.types.d.ts +144 -0
- package/dist/apps/signstack-cli/src/types/yaml.types.js +2 -0
- package/dist/apps/signstack-cli/src/types/yaml.types.js.map +1 -0
- package/dist/libs/common/base/src/index.d.ts +14 -0
- package/dist/libs/common/base/src/index.js +44 -0
- package/dist/libs/common/base/src/index.js.map +1 -0
- package/dist/libs/common/base/src/lib/address.util.d.ts +12 -0
- package/dist/libs/common/base/src/lib/address.util.js +55 -0
- package/dist/libs/common/base/src/lib/address.util.js.map +1 -0
- package/dist/libs/common/base/src/lib/country-code-data.d.ts +5 -0
- package/dist/libs/common/base/src/lib/country-code-data.js +1256 -0
- package/dist/libs/common/base/src/lib/country-code-data.js.map +1 -0
- package/dist/libs/common/base/src/lib/date.util.d.ts +13 -0
- package/dist/libs/common/base/src/lib/date.util.js +135 -0
- package/dist/libs/common/base/src/lib/date.util.js.map +1 -0
- package/dist/libs/common/base/src/lib/headers.d.ts +1 -0
- package/dist/libs/common/base/src/lib/headers.js +5 -0
- package/dist/libs/common/base/src/lib/headers.js.map +1 -0
- package/dist/libs/common/base/src/lib/jsonata.service.d.ts +32 -0
- package/dist/libs/common/base/src/lib/jsonata.service.js +207 -0
- package/dist/libs/common/base/src/lib/jsonata.service.js.map +1 -0
- package/dist/libs/common/base/src/lib/key-validation.constants.d.ts +37 -0
- package/dist/libs/common/base/src/lib/key-validation.constants.js +144 -0
- package/dist/libs/common/base/src/lib/key-validation.constants.js.map +1 -0
- package/dist/libs/common/base/src/lib/phone-util.d.ts +16 -0
- package/dist/libs/common/base/src/lib/phone-util.js +61 -0
- package/dist/libs/common/base/src/lib/phone-util.js.map +1 -0
- package/dist/libs/common/base/src/lib/schema-validation.util.d.ts +24 -0
- package/dist/libs/common/base/src/lib/schema-validation.util.js +155 -0
- package/dist/libs/common/base/src/lib/schema-validation.util.js.map +1 -0
- package/dist/libs/common/base/src/lib/string-builder.d.ts +48 -0
- package/dist/libs/common/base/src/lib/string-builder.js +90 -0
- package/dist/libs/common/base/src/lib/string-builder.js.map +1 -0
- package/dist/libs/common/base/src/lib/util.d.ts +20 -0
- package/dist/libs/common/base/src/lib/util.js +110 -0
- package/dist/libs/common/base/src/lib/util.js.map +1 -0
- package/dist/libs/signstack/base/schemas/asset.schema.json +220 -0
- package/dist/libs/signstack/base/schemas/blueprint.schema.json +485 -0
- package/dist/libs/signstack/base/schemas/jsonata-function.schema.json +185 -0
- package/dist/libs/signstack/base/schemas/schema.schema.json +97 -0
- package/dist/libs/signstack/base/schemas/template.schema.json +295 -0
- package/dist/libs/signstack/base/src/index.d.ts +28 -0
- package/dist/libs/signstack/base/src/index.js +32 -0
- package/dist/libs/signstack/base/src/index.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/constants.d.ts +123 -0
- package/dist/libs/signstack/base/src/lib/constants.js +131 -0
- package/dist/libs/signstack/base/src/lib/constants.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/hash.util.d.ts +58 -0
- package/dist/libs/signstack/base/src/lib/hash.util.js +90 -0
- package/dist/libs/signstack/base/src/lib/hash.util.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/is-schema-renderable.util.d.ts +29 -0
- package/dist/libs/signstack/base/src/lib/is-schema-renderable.util.js +93 -0
- package/dist/libs/signstack/base/src/lib/is-schema-renderable.util.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/ai-chat.d.ts +41 -0
- package/dist/libs/signstack/base/src/lib/models/ai-chat.js +3 -0
- package/dist/libs/signstack/base/src/lib/models/ai-chat.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/api-key.d.ts +54 -0
- package/dist/libs/signstack/base/src/lib/models/api-key.js +18 -0
- package/dist/libs/signstack/base/src/lib/models/api-key.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/asset.d.ts +101 -0
- package/dist/libs/signstack/base/src/lib/models/asset.js +11 -0
- package/dist/libs/signstack/base/src/lib/models/asset.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/auth.d.ts +142 -0
- package/dist/libs/signstack/base/src/lib/models/auth.js +35 -0
- package/dist/libs/signstack/base/src/lib/models/auth.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/base.d.ts +134 -0
- package/dist/libs/signstack/base/src/lib/models/base.js +71 -0
- package/dist/libs/signstack/base/src/lib/models/base.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/blueprint.d.ts +311 -0
- package/dist/libs/signstack/base/src/lib/models/blueprint.js +9 -0
- package/dist/libs/signstack/base/src/lib/models/blueprint.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/file.d.ts +75 -0
- package/dist/libs/signstack/base/src/lib/models/file.js +9 -0
- package/dist/libs/signstack/base/src/lib/models/file.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/jsonata-function.d.ts +111 -0
- package/dist/libs/signstack/base/src/lib/models/jsonata-function.js +19 -0
- package/dist/libs/signstack/base/src/lib/models/jsonata-function.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/marketplace-listing.d.ts +132 -0
- package/dist/libs/signstack/base/src/lib/models/marketplace-listing.js +22 -0
- package/dist/libs/signstack/base/src/lib/models/marketplace-listing.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/membership.d.ts +127 -0
- package/dist/libs/signstack/base/src/lib/models/membership.js +22 -0
- package/dist/libs/signstack/base/src/lib/models/membership.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/namespace.d.ts +87 -0
- package/dist/libs/signstack/base/src/lib/models/namespace.js +57 -0
- package/dist/libs/signstack/base/src/lib/models/namespace.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/organization.d.ts +79 -0
- package/dist/libs/signstack/base/src/lib/models/organization.js +41 -0
- package/dist/libs/signstack/base/src/lib/models/organization.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/render-job.d.ts +88 -0
- package/dist/libs/signstack/base/src/lib/models/render-job.js +3 -0
- package/dist/libs/signstack/base/src/lib/models/render-job.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/resource-edge.d.ts +60 -0
- package/dist/libs/signstack/base/src/lib/models/resource-edge.js +202 -0
- package/dist/libs/signstack/base/src/lib/models/resource-edge.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/scenario.d.ts +138 -0
- package/dist/libs/signstack/base/src/lib/models/scenario.js +14 -0
- package/dist/libs/signstack/base/src/lib/models/scenario.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/schema.d.ts +131 -0
- package/dist/libs/signstack/base/src/lib/models/schema.js +44 -0
- package/dist/libs/signstack/base/src/lib/models/schema.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/shareable-link.d.ts +215 -0
- package/dist/libs/signstack/base/src/lib/models/shareable-link.js +27 -0
- package/dist/libs/signstack/base/src/lib/models/shareable-link.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/subscription.d.ts +279 -0
- package/dist/libs/signstack/base/src/lib/models/subscription.js +105 -0
- package/dist/libs/signstack/base/src/lib/models/subscription.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/template.d.ts +248 -0
- package/dist/libs/signstack/base/src/lib/models/template.js +32 -0
- package/dist/libs/signstack/base/src/lib/models/template.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/user.d.ts +30 -0
- package/dist/libs/signstack/base/src/lib/models/user.js +3 -0
- package/dist/libs/signstack/base/src/lib/models/user.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/webhook.d.ts +223 -0
- package/dist/libs/signstack/base/src/lib/models/webhook.js +62 -0
- package/dist/libs/signstack/base/src/lib/models/webhook.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/models/workflow.d.ts +917 -0
- package/dist/libs/signstack/base/src/lib/models/workflow.js +152 -0
- package/dist/libs/signstack/base/src/lib/models/workflow.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/util.d.ts +92 -0
- package/dist/libs/signstack/base/src/lib/util.js +406 -0
- package/dist/libs/signstack/base/src/lib/util.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/dependency-graph.d.ts +94 -0
- package/dist/libs/signstack/base/src/lib/validation/dependency-graph.js +446 -0
- package/dist/libs/signstack/base/src/lib/validation/dependency-graph.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/graph.types.d.ts +57 -0
- package/dist/libs/signstack/base/src/lib/validation/graph.types.js +8 -0
- package/dist/libs/signstack/base/src/lib/validation/graph.types.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/index.d.ts +9 -0
- package/dist/libs/signstack/base/src/lib/validation/index.js +23 -0
- package/dist/libs/signstack/base/src/lib/validation/index.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/resource-schemas.d.ts +3 -0
- package/dist/libs/signstack/base/src/lib/validation/resource-schemas.js +27 -0
- package/dist/libs/signstack/base/src/lib/validation/resource-schemas.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validation.types.d.ts +57 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validation.types.js +57 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validation.types.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validator.d.ts +38 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validator.js +146 -0
- package/dist/libs/signstack/base/src/lib/validation/schema-validator.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-dependencies.d.ts +22 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-dependencies.js +69 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-dependencies.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-resource-tree.d.ts +37 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-resource-tree.js +250 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-resource-tree.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-template-inputs.d.ts +24 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-template-inputs.js +98 -0
- package/dist/libs/signstack/base/src/lib/validation/validate-template-inputs.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/validation/yaml-document-utils.d.ts +12 -0
- package/dist/libs/signstack/base/src/lib/validation/yaml-document-utils.js +50 -0
- package/dist/libs/signstack/base/src/lib/validation/yaml-document-utils.js.map +1 -0
- package/dist/libs/signstack/base/src/lib/yaml-spec-converter.d.ts +101 -0
- package/dist/libs/signstack/base/src/lib/yaml-spec-converter.js +998 -0
- package/dist/libs/signstack/base/src/lib/yaml-spec-converter.js.map +1 -0
- package/oclif.manifest.json +822 -0
- package/package.json +101 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import boxen from 'boxen';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { Command } from '@oclif/core';
|
|
4
|
+
export default class Test extends Command {
|
|
5
|
+
static description = 'Test the CLI installation';
|
|
6
|
+
static examples = ['<%= config.bin %> test'];
|
|
7
|
+
async run() {
|
|
8
|
+
await this.parse(Test);
|
|
9
|
+
const message = [
|
|
10
|
+
chalk.bold.cyan('Modern Sign CLI'),
|
|
11
|
+
'',
|
|
12
|
+
`${chalk.green('✓')} CLI is installed and working correctly`,
|
|
13
|
+
'',
|
|
14
|
+
chalk.dim(`Version: ${this.config.version}`),
|
|
15
|
+
chalk.dim(`Node: ${process.version}`),
|
|
16
|
+
chalk.dim(`Platform: ${process.platform}-${process.arch}`),
|
|
17
|
+
].join('\n');
|
|
18
|
+
this.log(boxen(message, {
|
|
19
|
+
padding: 1,
|
|
20
|
+
borderColor: 'cyan',
|
|
21
|
+
borderStyle: 'round',
|
|
22
|
+
}));
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../../../../src/commands/test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAEtC,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,OAAO;IACvC,MAAM,CAAU,WAAW,GAAG,2BAA2B,CAAC;IAE1D,MAAM,CAAU,QAAQ,GAAG,CAAC,wBAAwB,CAAC,CAAC;IAE/C,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAEvB,MAAM,OAAO,GAAG;YACd,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC;YAClC,EAAE;YACF,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,yCAAyC;YAC5D,EAAE;YACF,KAAK,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAC5C,KAAK,CAAC,GAAG,CAAC,SAAS,OAAO,CAAC,OAAO,EAAE,CAAC;YACrC,KAAK,CAAC,GAAG,CAAC,aAAa,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;SAC3D,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAEb,IAAI,CAAC,GAAG,CACN,KAAK,CAAC,OAAO,EAAE;YACb,OAAO,EAAE,CAAC;YACV,WAAW,EAAE,MAAM;YACnB,WAAW,EAAE,OAAO;SACrB,CAAC,CACH,CAAC;IACJ,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { AuthenticatedCommand } from '../lib/base-command.js';
|
|
2
|
+
export default class Validate extends AuthenticatedCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: {
|
|
5
|
+
command: string;
|
|
6
|
+
description: string;
|
|
7
|
+
}[];
|
|
8
|
+
static args: {
|
|
9
|
+
resource: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
10
|
+
};
|
|
11
|
+
static flags: {
|
|
12
|
+
kind: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
dir: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
'no-deps': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
'no-remote': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
17
|
+
json: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
'api-url': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
};
|
|
20
|
+
run(): Promise<void>;
|
|
21
|
+
private runSingle;
|
|
22
|
+
/**
|
|
23
|
+
* Resolve the resource kind — from --kind flag or inferred from YAML files.
|
|
24
|
+
*/
|
|
25
|
+
private resolveResourceKind;
|
|
26
|
+
/**
|
|
27
|
+
* Validate that all dependencies exist — locally in the graph or remotely on the API.
|
|
28
|
+
* Dependencies found on the API are reported as warnings (not errors).
|
|
29
|
+
*/
|
|
30
|
+
private validateDependencies;
|
|
31
|
+
/**
|
|
32
|
+
* Validate that spec.file references exist (scoped to given IDs)
|
|
33
|
+
*/
|
|
34
|
+
private validateFileReferences;
|
|
35
|
+
/**
|
|
36
|
+
* Validate that versioned resources do not depend on draft resources.
|
|
37
|
+
*/
|
|
38
|
+
private validateDraftDependencies;
|
|
39
|
+
/**
|
|
40
|
+
* Print the dependency graph for the subtree
|
|
41
|
+
*/
|
|
42
|
+
private printDependencyGraph;
|
|
43
|
+
/**
|
|
44
|
+
* Print cycle detection errors
|
|
45
|
+
*/
|
|
46
|
+
private printCycleErrors;
|
|
47
|
+
/**
|
|
48
|
+
* Print validation result for a single document
|
|
49
|
+
*/
|
|
50
|
+
private printResult;
|
|
51
|
+
/**
|
|
52
|
+
* Print resource validation summary
|
|
53
|
+
*/
|
|
54
|
+
private printResourceSummary;
|
|
55
|
+
/**
|
|
56
|
+
* Print simple summary (used for early exit on parse errors)
|
|
57
|
+
*/
|
|
58
|
+
private printSummary;
|
|
59
|
+
}
|
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { dirname, resolve } from 'node:path';
|
|
4
|
+
import pc from 'picocolors';
|
|
5
|
+
import { DependencyGraph, } from '@signstack/base';
|
|
6
|
+
import { AuthenticatedCommand } from '../lib/base-command.js';
|
|
7
|
+
import { promptResourceSelection } from '../lib/resource-scanner.js';
|
|
8
|
+
import { getSchemaValidator } from '../lib/schema-validator.js';
|
|
9
|
+
import { SCHEMA_KIND_TO_BACKEND, KIND_TO_ENDPOINT, } from '../lib/resource-puller.js';
|
|
10
|
+
import { discoverYamlFiles, parseAllYamlFiles, SEPARATOR_LENGTH, } from '../lib/yaml-document-parser.js';
|
|
11
|
+
import { CLI_FLAG_TO_SCHEMA_KIND, getAvailableSchemaKinds, SchemaKind, SCHEMA_FLAG_OPTIONS, ValidationErrorKeyword, } from '../types/schema.types.js';
|
|
12
|
+
export default class Validate extends AuthenticatedCommand {
|
|
13
|
+
static description = 'Validate resources and their dependencies against SignStack schemas with dependency analysis.';
|
|
14
|
+
static examples = [
|
|
15
|
+
{
|
|
16
|
+
command: '<%= config.bin %> validate my_blueprint@1.0.0 --kind blueprint',
|
|
17
|
+
description: 'Validate a blueprint and all its dependencies in the current directory',
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
command: '<%= config.bin %> validate my_template@1.0.0 -d ./my-project',
|
|
21
|
+
description: 'Validate a template (kind inferred) from a specific directory',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
command: '<%= config.bin %> validate my_blueprint@1.0.0 --kind blueprint --verbose',
|
|
25
|
+
description: 'Validate with detailed output including dependency graph',
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
command: '<%= config.bin %> validate my_blueprint@1.0.0 --kind blueprint --no-deps',
|
|
29
|
+
description: 'Validate without dependency ordering (faster)',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
static args = {
|
|
33
|
+
resource: Args.string({
|
|
34
|
+
description: 'Resource reference as key@version (e.g., my_blueprint@1.0.0)',
|
|
35
|
+
required: false,
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
static flags = {
|
|
39
|
+
...AuthenticatedCommand.baseFlags,
|
|
40
|
+
kind: Flags.string({
|
|
41
|
+
char: 'k',
|
|
42
|
+
description: 'Resource kind (optional — inferred from YAML files if omitted)',
|
|
43
|
+
required: false,
|
|
44
|
+
options: SCHEMA_FLAG_OPTIONS,
|
|
45
|
+
}),
|
|
46
|
+
dir: Flags.string({
|
|
47
|
+
char: 'd',
|
|
48
|
+
description: 'Directory containing YAML resource files. The specified resource and all its dependencies must be present in this directory.',
|
|
49
|
+
default: '.',
|
|
50
|
+
}),
|
|
51
|
+
verbose: Flags.boolean({
|
|
52
|
+
char: 'v',
|
|
53
|
+
description: 'Show detailed validation output',
|
|
54
|
+
default: false,
|
|
55
|
+
}),
|
|
56
|
+
'no-deps': Flags.boolean({
|
|
57
|
+
description: 'Skip dependency ordering and validation',
|
|
58
|
+
default: false,
|
|
59
|
+
}),
|
|
60
|
+
'no-remote': Flags.boolean({
|
|
61
|
+
description: 'Skip checking missing dependencies against the API (local only)',
|
|
62
|
+
default: false,
|
|
63
|
+
}),
|
|
64
|
+
json: Flags.boolean({
|
|
65
|
+
description: 'Output in JSON format',
|
|
66
|
+
default: false,
|
|
67
|
+
}),
|
|
68
|
+
};
|
|
69
|
+
async run() {
|
|
70
|
+
const { args, flags } = await this.parse(Validate);
|
|
71
|
+
return this.runSingle(args, flags);
|
|
72
|
+
}
|
|
73
|
+
// ─── Single resource mode ───────────────────────────────────
|
|
74
|
+
async runSingle(args, flags) {
|
|
75
|
+
// Step 1: Resolve directory
|
|
76
|
+
const folderPath = resolve(flags.dir);
|
|
77
|
+
if (!existsSync(folderPath)) {
|
|
78
|
+
this.error(`Directory not found: ${folderPath}`, { exit: 1 });
|
|
79
|
+
}
|
|
80
|
+
// Step 2: Parse resource reference or prompt for selection
|
|
81
|
+
let ref;
|
|
82
|
+
let selectedKind;
|
|
83
|
+
if (args.resource) {
|
|
84
|
+
ref = this.sanitizeInput(args.resource);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
if (flags.json) {
|
|
88
|
+
this.error('Provide a resource reference when using --json.', {
|
|
89
|
+
exit: 1,
|
|
90
|
+
suggestions: [
|
|
91
|
+
'signstack validate my_blueprint@1.0.0 --json',
|
|
92
|
+
],
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
const selected = await promptResourceSelection(folderPath, getAvailableSchemaKinds(), 'Select a resource to validate');
|
|
96
|
+
if (!selected) {
|
|
97
|
+
this.error('No resources found in the specified directory.', {
|
|
98
|
+
exit: 1,
|
|
99
|
+
suggestions: [
|
|
100
|
+
'Ensure the directory contains valid SignStack YAML files',
|
|
101
|
+
'Use -d to specify a different directory',
|
|
102
|
+
],
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
ref = selected.ref;
|
|
106
|
+
selectedKind = selected.kind;
|
|
107
|
+
}
|
|
108
|
+
const { key, version: parsedVersion } = this.parseResourceRef(ref, 'resource', true);
|
|
109
|
+
const version = parsedVersion;
|
|
110
|
+
// ── Step 3: Discover and parse YAML files ────────────────────
|
|
111
|
+
const filePaths = await discoverYamlFiles(folderPath);
|
|
112
|
+
if (filePaths.length === 0) {
|
|
113
|
+
this.error('No YAML files found in the specified directory', {
|
|
114
|
+
exit: 1,
|
|
115
|
+
suggestions: ['Ensure the directory contains .yaml or .yml files'],
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
if (flags.verbose) {
|
|
119
|
+
this.log(pc.dim(`\nFound ${filePaths.length} YAML file(s) in ${folderPath}\n`));
|
|
120
|
+
}
|
|
121
|
+
const { documents, parseErrors } = parseAllYamlFiles(filePaths);
|
|
122
|
+
if (documents.length === 0 && parseErrors.length > 0) {
|
|
123
|
+
this.printSummary({
|
|
124
|
+
total: parseErrors.length,
|
|
125
|
+
passed: 0,
|
|
126
|
+
failed: parseErrors.length,
|
|
127
|
+
results: parseErrors,
|
|
128
|
+
hasCycles: false,
|
|
129
|
+
});
|
|
130
|
+
this.exit(1);
|
|
131
|
+
}
|
|
132
|
+
// ── Step 4: Resolve resource kind ────────────────────────────
|
|
133
|
+
const schemaKind = selectedKind ?? this.resolveResourceKind(flags.kind, key, version, documents);
|
|
134
|
+
// ── Step 5: Build dependency graph and extract subtree ────────
|
|
135
|
+
const graph = DependencyGraph.fromDocuments(documents);
|
|
136
|
+
const rootId = DependencyGraph.createId(schemaKind, key, version);
|
|
137
|
+
if (!graph.nodes.has(rootId)) {
|
|
138
|
+
this.error(`Resource ${schemaKind}:${key}@${version} not found in ${folderPath}.`, {
|
|
139
|
+
exit: 1,
|
|
140
|
+
suggestions: [
|
|
141
|
+
'Ensure the YAML file for this resource is present in the directory',
|
|
142
|
+
`Check that metadata.key is "${key}" and metadata.version is "${version}"`,
|
|
143
|
+
],
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
const subtreeIds = graph.getTransitiveDependencies(rootId);
|
|
147
|
+
this.log(pc.cyan(`\nValidating ${schemaKind}:${key}@${version} and ${subtreeIds.size - 1} dependenc${subtreeIds.size - 1 === 1 ? 'y' : 'ies'}\n`));
|
|
148
|
+
// Display dependency graph
|
|
149
|
+
this.printDependencyGraph(graph, subtreeIds, flags.verbose);
|
|
150
|
+
// ── Step 6: Determine validation order ───────────────────────
|
|
151
|
+
let filteredOrder;
|
|
152
|
+
let sortResult;
|
|
153
|
+
if (flags['no-deps']) {
|
|
154
|
+
filteredOrder = Array.from(subtreeIds);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
sortResult = graph.topologicalSort();
|
|
158
|
+
filteredOrder = sortResult.order.filter((id) => subtreeIds.has(id));
|
|
159
|
+
// Add any subtree nodes not in sort result (cycle members)
|
|
160
|
+
const orderedSet = new Set(filteredOrder);
|
|
161
|
+
for (const id of subtreeIds) {
|
|
162
|
+
if (!orderedSet.has(id) && graph.nodes.has(id)) {
|
|
163
|
+
filteredOrder.push(id);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
// ── Step 7: Run validations ──────────────────────────────────
|
|
168
|
+
const validator = getSchemaValidator();
|
|
169
|
+
const results = [...parseErrors];
|
|
170
|
+
// Schema validation in topological order
|
|
171
|
+
for (const resourceId of filteredOrder) {
|
|
172
|
+
const doc = graph.nodes.get(resourceId);
|
|
173
|
+
if (!doc)
|
|
174
|
+
continue;
|
|
175
|
+
const result = validator.validate(doc.content, doc.filePath, doc.kind, doc.documentIndex);
|
|
176
|
+
results.push(result);
|
|
177
|
+
this.printResult(result, flags.verbose);
|
|
178
|
+
}
|
|
179
|
+
// Dependency and file reference validation (if not skipped)
|
|
180
|
+
if (!flags['no-deps']) {
|
|
181
|
+
const depErrors = await this.validateDependencies(graph, subtreeIds, flags.verbose, flags['no-remote']);
|
|
182
|
+
results.push(...depErrors);
|
|
183
|
+
const fileRefErrors = this.validateFileReferences(graph, subtreeIds, flags.verbose);
|
|
184
|
+
results.push(...fileRefErrors);
|
|
185
|
+
const draftErrors = this.validateDraftDependencies(graph, subtreeIds, flags.verbose);
|
|
186
|
+
results.push(...draftErrors);
|
|
187
|
+
}
|
|
188
|
+
// ── Step 8: Build and print summary ──────────────────────────
|
|
189
|
+
const hasCycles = sortResult ? !sortResult.isAcyclic : false;
|
|
190
|
+
// Only report cycles that involve subtree resources
|
|
191
|
+
const relevantCycles = sortResult?.cycles?.filter((cycle) => cycle.some((id) => subtreeIds.has(id)));
|
|
192
|
+
const summary = {
|
|
193
|
+
total: results.length,
|
|
194
|
+
passed: results.filter((r) => r.valid).length,
|
|
195
|
+
failed: results.filter((r) => !r.valid).length,
|
|
196
|
+
results,
|
|
197
|
+
graphStats: graph.getStats(),
|
|
198
|
+
hasCycles: (relevantCycles?.length ?? 0) > 0,
|
|
199
|
+
cycles: relevantCycles,
|
|
200
|
+
};
|
|
201
|
+
if (flags.json) {
|
|
202
|
+
this.log(JSON.stringify({
|
|
203
|
+
total: summary.total,
|
|
204
|
+
passed: summary.passed,
|
|
205
|
+
failed: summary.failed,
|
|
206
|
+
hasCycles: summary.hasCycles,
|
|
207
|
+
cycles: summary.cycles,
|
|
208
|
+
graphStats: summary.graphStats,
|
|
209
|
+
results: summary.results.map((r) => ({
|
|
210
|
+
valid: r.valid,
|
|
211
|
+
filePath: r.filePath,
|
|
212
|
+
schemaKind: r.schemaKind,
|
|
213
|
+
resourceKey: r.resourceKey,
|
|
214
|
+
resourceVersion: r.resourceVersion,
|
|
215
|
+
errors: r.errors,
|
|
216
|
+
})),
|
|
217
|
+
}));
|
|
218
|
+
if (summary.failed > 0 || summary.hasCycles)
|
|
219
|
+
this.exit(1);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (summary.hasCycles && summary.cycles && summary.cycles.length > 0) {
|
|
223
|
+
this.printCycleErrors(summary.cycles);
|
|
224
|
+
}
|
|
225
|
+
this.printResourceSummary(summary, flags.verbose);
|
|
226
|
+
if (summary.failed > 0 || summary.hasCycles) {
|
|
227
|
+
this.exit(1);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// ─── Kind Resolution ─────────────────────────────────────────
|
|
231
|
+
/**
|
|
232
|
+
* Resolve the resource kind — from --kind flag or inferred from YAML files.
|
|
233
|
+
*/
|
|
234
|
+
resolveResourceKind(kindFlag, key, version, documents) {
|
|
235
|
+
if (kindFlag) {
|
|
236
|
+
return CLI_FLAG_TO_SCHEMA_KIND[kindFlag];
|
|
237
|
+
}
|
|
238
|
+
const matches = documents.filter((doc) => doc.key === key && doc.version === version);
|
|
239
|
+
if (matches.length === 0) {
|
|
240
|
+
this.error(`No resource with key "${key}" and version "${version}" found in the directory.`, {
|
|
241
|
+
exit: 1,
|
|
242
|
+
suggestions: [
|
|
243
|
+
'Check that your YAML files contain a resource with the specified key and version',
|
|
244
|
+
'Use --kind to specify the resource kind explicitly',
|
|
245
|
+
],
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
if (matches.length === 1) {
|
|
249
|
+
this.log(pc.dim(`Inferred kind: ${matches[0].kind} (from ${matches[0].filePath})\n`));
|
|
250
|
+
return matches[0].kind;
|
|
251
|
+
}
|
|
252
|
+
const kindList = matches.map((m) => m.kind).join(', ');
|
|
253
|
+
this.error(`Multiple resources found for ${key}@${version}: ${kindList}. Use --kind to disambiguate.`, {
|
|
254
|
+
exit: 1,
|
|
255
|
+
suggestions: matches.map((m) => `validate ${key}@${version} --kind ${Object.entries(CLI_FLAG_TO_SCHEMA_KIND).find(([, v]) => v === m.kind)?.[0] ?? m.kind.toLowerCase()}`),
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
// ─── Dependency & File Ref Validation ────────────────────────
|
|
259
|
+
/**
|
|
260
|
+
* Validate that all dependencies exist — locally in the graph or remotely on the API.
|
|
261
|
+
* Dependencies found on the API are reported as warnings (not errors).
|
|
262
|
+
*/
|
|
263
|
+
async validateDependencies(graph, scopeIds, verbose, noRemote = false) {
|
|
264
|
+
const errors = [];
|
|
265
|
+
const missing = graph.getMissingDependencies();
|
|
266
|
+
// Collect all missing deps to check against API in batch
|
|
267
|
+
const missingToCheck = [];
|
|
268
|
+
for (const [sourceId, missingDeps] of missing) {
|
|
269
|
+
if (!scopeIds.has(sourceId))
|
|
270
|
+
continue;
|
|
271
|
+
const sourceDoc = graph.nodes.get(sourceId);
|
|
272
|
+
if (!sourceDoc)
|
|
273
|
+
continue;
|
|
274
|
+
for (const missingId of missingDeps) {
|
|
275
|
+
const { kind, key, version } = DependencyGraph.parseId(missingId);
|
|
276
|
+
const ref = sourceDoc.references.find((r) => r.key === key && r.version === version && r.targetKind === kind);
|
|
277
|
+
missingToCheck.push({
|
|
278
|
+
sourceDoc,
|
|
279
|
+
missingId,
|
|
280
|
+
kind,
|
|
281
|
+
key,
|
|
282
|
+
version,
|
|
283
|
+
sourcePath: ref?.sourcePath ?? '/',
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
if (missingToCheck.length === 0)
|
|
288
|
+
return errors;
|
|
289
|
+
if (noRemote) {
|
|
290
|
+
// --no-remote: all missing are errors without API check
|
|
291
|
+
for (const dep of missingToCheck) {
|
|
292
|
+
const error = {
|
|
293
|
+
valid: false,
|
|
294
|
+
errors: [
|
|
295
|
+
{
|
|
296
|
+
path: dep.sourcePath,
|
|
297
|
+
message: `Referenced ${dep.kind} '${dep.key}@${dep.version}' not found locally`,
|
|
298
|
+
keyword: ValidationErrorKeyword.DependencyMissing,
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
schemaKind: dep.sourceDoc.kind,
|
|
302
|
+
filePath: dep.sourceDoc.filePath,
|
|
303
|
+
documentIndex: dep.sourceDoc.documentIndex,
|
|
304
|
+
resourceKey: dep.sourceDoc.key,
|
|
305
|
+
resourceVersion: dep.sourceDoc.version,
|
|
306
|
+
};
|
|
307
|
+
errors.push(error);
|
|
308
|
+
this.printResult(error, verbose);
|
|
309
|
+
}
|
|
310
|
+
return errors;
|
|
311
|
+
}
|
|
312
|
+
// Check each missing dep against the API
|
|
313
|
+
const remoteResults = await Promise.all(missingToCheck.map(async (dep) => {
|
|
314
|
+
const backendKind = SCHEMA_KIND_TO_BACKEND[dep.kind];
|
|
315
|
+
if (!backendKind)
|
|
316
|
+
return { ...dep, existsRemotely: false };
|
|
317
|
+
try {
|
|
318
|
+
const endpoint = KIND_TO_ENDPOINT[backendKind];
|
|
319
|
+
await this.apiClient.get(`/v1/orgs/${this.cliConfig.orgId}/namespaces/${this.cliConfig.namespaceKey}/${endpoint}/${encodeURIComponent(dep.key)}?version=${encodeURIComponent(dep.version)}`);
|
|
320
|
+
return { ...dep, existsRemotely: true };
|
|
321
|
+
}
|
|
322
|
+
catch {
|
|
323
|
+
return { ...dep, existsRemotely: false };
|
|
324
|
+
}
|
|
325
|
+
}));
|
|
326
|
+
for (const dep of remoteResults) {
|
|
327
|
+
if (dep.existsRemotely) {
|
|
328
|
+
// Dependency exists on the API — informational only
|
|
329
|
+
if (verbose) {
|
|
330
|
+
this.log(pc.dim(` ${dep.kind}:${dep.key}@${dep.version} — not local, found on API`));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
// Dependency missing both locally and remotely — error
|
|
335
|
+
const error = {
|
|
336
|
+
valid: false,
|
|
337
|
+
errors: [
|
|
338
|
+
{
|
|
339
|
+
path: dep.sourcePath,
|
|
340
|
+
message: `Referenced ${dep.kind} '${dep.key}@${dep.version}' not found locally or on the API`,
|
|
341
|
+
keyword: ValidationErrorKeyword.DependencyMissing,
|
|
342
|
+
},
|
|
343
|
+
],
|
|
344
|
+
schemaKind: dep.sourceDoc.kind,
|
|
345
|
+
filePath: dep.sourceDoc.filePath,
|
|
346
|
+
documentIndex: dep.sourceDoc.documentIndex,
|
|
347
|
+
resourceKey: dep.sourceDoc.key,
|
|
348
|
+
resourceVersion: dep.sourceDoc.version,
|
|
349
|
+
};
|
|
350
|
+
errors.push(error);
|
|
351
|
+
this.printResult(error, verbose);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return errors;
|
|
355
|
+
}
|
|
356
|
+
/**
|
|
357
|
+
* Validate that spec.file references exist (scoped to given IDs)
|
|
358
|
+
*/
|
|
359
|
+
validateFileReferences(graph, scopeIds, verbose) {
|
|
360
|
+
const errors = [];
|
|
361
|
+
for (const id of scopeIds) {
|
|
362
|
+
const doc = graph.nodes.get(id);
|
|
363
|
+
if (!doc)
|
|
364
|
+
continue;
|
|
365
|
+
if (doc.kind !== SchemaKind.Schema && doc.kind !== SchemaKind.Asset) {
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
const spec = doc.content['spec'];
|
|
369
|
+
const filePath = spec?.['file'];
|
|
370
|
+
if (!filePath)
|
|
371
|
+
continue;
|
|
372
|
+
const baseDir = dirname(doc.filePath);
|
|
373
|
+
const resolvedPath = resolve(baseDir, filePath);
|
|
374
|
+
if (!existsSync(resolvedPath)) {
|
|
375
|
+
const error = {
|
|
376
|
+
valid: false,
|
|
377
|
+
errors: [
|
|
378
|
+
{
|
|
379
|
+
path: 'spec.file',
|
|
380
|
+
message: `Referenced file '${filePath}' not found (resolved: ${resolvedPath})`,
|
|
381
|
+
keyword: ValidationErrorKeyword.FileReferenceMissing,
|
|
382
|
+
},
|
|
383
|
+
],
|
|
384
|
+
schemaKind: doc.kind,
|
|
385
|
+
filePath: doc.filePath,
|
|
386
|
+
documentIndex: doc.documentIndex,
|
|
387
|
+
resourceKey: doc.key,
|
|
388
|
+
resourceVersion: doc.version,
|
|
389
|
+
};
|
|
390
|
+
errors.push(error);
|
|
391
|
+
this.printResult(error, verbose);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
return errors;
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Validate that versioned resources do not depend on draft resources.
|
|
398
|
+
*/
|
|
399
|
+
validateDraftDependencies(graph, scopeIds, verbose) {
|
|
400
|
+
const errors = [];
|
|
401
|
+
const draftErrors = graph.validateDraftDependencies();
|
|
402
|
+
for (const err of draftErrors) {
|
|
403
|
+
if (!scopeIds.has(err.sourceId))
|
|
404
|
+
continue;
|
|
405
|
+
const sourceDoc = graph.nodes.get(err.sourceId);
|
|
406
|
+
if (!sourceDoc)
|
|
407
|
+
continue;
|
|
408
|
+
const error = {
|
|
409
|
+
valid: false,
|
|
410
|
+
errors: [
|
|
411
|
+
{
|
|
412
|
+
path: '/',
|
|
413
|
+
message: err.message,
|
|
414
|
+
keyword: ValidationErrorKeyword.DraftDependency,
|
|
415
|
+
},
|
|
416
|
+
],
|
|
417
|
+
schemaKind: sourceDoc.kind,
|
|
418
|
+
filePath: sourceDoc.filePath,
|
|
419
|
+
documentIndex: sourceDoc.documentIndex,
|
|
420
|
+
resourceKey: sourceDoc.key,
|
|
421
|
+
resourceVersion: sourceDoc.version,
|
|
422
|
+
};
|
|
423
|
+
errors.push(error);
|
|
424
|
+
this.printResult(error, verbose);
|
|
425
|
+
}
|
|
426
|
+
return errors;
|
|
427
|
+
}
|
|
428
|
+
// ─── Display Helpers ─────────────────────────────────────────
|
|
429
|
+
/**
|
|
430
|
+
* Print the dependency graph for the subtree
|
|
431
|
+
*/
|
|
432
|
+
printDependencyGraph(graph, subtreeIds, verbose) {
|
|
433
|
+
if (!verbose)
|
|
434
|
+
return;
|
|
435
|
+
this.log(pc.cyan('Dependency Graph'));
|
|
436
|
+
// Group subtree nodes by kind
|
|
437
|
+
const nodesByKind = new Map();
|
|
438
|
+
for (const id of subtreeIds) {
|
|
439
|
+
if (!graph.nodes.has(id))
|
|
440
|
+
continue;
|
|
441
|
+
const { kind } = DependencyGraph.parseId(id);
|
|
442
|
+
if (!nodesByKind.has(kind)) {
|
|
443
|
+
nodesByKind.set(kind, []);
|
|
444
|
+
}
|
|
445
|
+
nodesByKind.get(kind).push(id);
|
|
446
|
+
}
|
|
447
|
+
const kindOrder = [
|
|
448
|
+
SchemaKind.Blueprint,
|
|
449
|
+
SchemaKind.Template,
|
|
450
|
+
SchemaKind.JsonataFunction,
|
|
451
|
+
SchemaKind.Schema,
|
|
452
|
+
SchemaKind.Asset,
|
|
453
|
+
];
|
|
454
|
+
for (const kind of kindOrder) {
|
|
455
|
+
const nodes = nodesByKind.get(kind);
|
|
456
|
+
if (!nodes || nodes.length === 0)
|
|
457
|
+
continue;
|
|
458
|
+
this.log(pc.yellow(` ${kind} (${nodes.length})`));
|
|
459
|
+
for (const id of nodes.sort()) {
|
|
460
|
+
const { key, version } = DependencyGraph.parseId(id);
|
|
461
|
+
const deps = graph.edges.get(id) ?? new Set();
|
|
462
|
+
const existingDeps = Array.from(deps).filter((d) => graph.nodes.has(d));
|
|
463
|
+
if (existingDeps.length === 0) {
|
|
464
|
+
this.log(pc.dim(` ├─ ${key}@${version}`));
|
|
465
|
+
}
|
|
466
|
+
else {
|
|
467
|
+
this.log(` ├─ ${key}@${version}`);
|
|
468
|
+
for (let i = 0; i < existingDeps.length; i++) {
|
|
469
|
+
const depId = existingDeps[i];
|
|
470
|
+
const { kind: depKind, key: depKey, version: depVersion, } = DependencyGraph.parseId(depId);
|
|
471
|
+
const prefix = i === existingDeps.length - 1 ? '└──' : '├──';
|
|
472
|
+
this.log(pc.dim(` │ ${prefix} ${depKind}:${depKey}@${depVersion}`));
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
this.log('');
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* Print cycle detection errors
|
|
481
|
+
*/
|
|
482
|
+
printCycleErrors(cycles) {
|
|
483
|
+
this.log('');
|
|
484
|
+
this.log(pc.red('Circular dependencies detected:'));
|
|
485
|
+
for (const cycle of cycles) {
|
|
486
|
+
const cycleStr = cycle
|
|
487
|
+
.map((id) => {
|
|
488
|
+
const { kind, key, version } = DependencyGraph.parseId(id);
|
|
489
|
+
return `${kind}:${key}@${version}`;
|
|
490
|
+
})
|
|
491
|
+
.join(' → ');
|
|
492
|
+
this.log(pc.red(` • ${cycleStr}`));
|
|
493
|
+
}
|
|
494
|
+
this.log('');
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* Print validation result for a single document
|
|
498
|
+
*/
|
|
499
|
+
printResult(result, verbose) {
|
|
500
|
+
const fileDisplay = result.resourceKey && result.resourceVersion
|
|
501
|
+
? `${result.filePath} [${result.resourceKey}@${result.resourceVersion}]`
|
|
502
|
+
: result.documentIndex !== undefined
|
|
503
|
+
? `${result.filePath} [document ${result.documentIndex + 1}]`
|
|
504
|
+
: result.filePath;
|
|
505
|
+
if (result.valid) {
|
|
506
|
+
this.log(`${pc.green('✓')} ${fileDisplay}`);
|
|
507
|
+
if (verbose) {
|
|
508
|
+
this.log(pc.dim(` Schema: ${result.schemaKind}`));
|
|
509
|
+
this.log('');
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
this.log(`${pc.red('✗')} ${fileDisplay}`);
|
|
514
|
+
this.log(pc.dim(` Schema: ${result.schemaKind}`));
|
|
515
|
+
this.log('');
|
|
516
|
+
this.log(pc.red(' Errors:'));
|
|
517
|
+
for (const error of result.errors) {
|
|
518
|
+
const path = error.path === '/' ? '(root)' : error.path;
|
|
519
|
+
this.log(` ${pc.red('•')} ${error.message}`);
|
|
520
|
+
this.log(pc.dim(` Path: ${path}`));
|
|
521
|
+
if (verbose && error.params) {
|
|
522
|
+
this.log(pc.dim(` Details: ${JSON.stringify(error.params)}`));
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
this.log('');
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/**
|
|
529
|
+
* Print resource validation summary
|
|
530
|
+
*/
|
|
531
|
+
printResourceSummary(summary, verbose) {
|
|
532
|
+
const { total, passed, failed, graphStats, hasCycles } = summary;
|
|
533
|
+
this.log(pc.dim('─'.repeat(SEPARATOR_LENGTH)));
|
|
534
|
+
if (verbose && graphStats) {
|
|
535
|
+
this.log(pc.dim(`\nGraph: ${graphStats.totalNodes} resources, ${graphStats.totalEdges} dependencies`));
|
|
536
|
+
}
|
|
537
|
+
if (failed === 0 && !hasCycles) {
|
|
538
|
+
this.log(pc.green(`\nValidation complete: ${total} document(s) checked, all passed ✓\n`));
|
|
539
|
+
}
|
|
540
|
+
else {
|
|
541
|
+
const parts = [`\nValidation complete: ${total} document(s) checked`];
|
|
542
|
+
if (passed > 0)
|
|
543
|
+
parts.push(pc.green(`${passed} passed`));
|
|
544
|
+
if (failed > 0)
|
|
545
|
+
parts.push(pc.red(`${failed} failed`));
|
|
546
|
+
if (hasCycles)
|
|
547
|
+
parts.push(pc.red('circular dependencies detected'));
|
|
548
|
+
this.log(parts.join(', ') + '\n');
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Print simple summary (used for early exit on parse errors)
|
|
553
|
+
*/
|
|
554
|
+
printSummary(summary) {
|
|
555
|
+
this.printResourceSummary(summary, false);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
//# sourceMappingURL=validate.js.map
|