{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "https://maibornwolff.github.io/codecharta/schemas/cc-json-2.0.schema.json", "title": "CodeCharta cc.json 2.0", "description": "The cc.json 2.0 wire format: { meta, files, lenses }. `files` is the identity layer (one root folder, nested children, each node carrying a stable id); `lenses` are additive analysis overlays joined to files by id. This is the analysis-side format `ccsh` emits and `ccsh check` validates. See dev_docs/cc-json-2.0-format.md for the prose spec.", "type": "object", "additionalProperties": false, "required": ["meta", "files", "lenses"], "properties": { "meta": { "$ref": "#/definitions/Meta" }, "files": { "description": "Exactly one root folder; the identity layer (no metrics on the node).", "type": "array", "minItems": 1, "maxItems": 1, "items": { "$ref": "#/definitions/FileNode" } }, "lenses": { "$ref": "#/definitions/Lenses" } }, "definitions": { "Meta": { "description": "Project metadata. `checksum` is an MD5 over the serialized files+lenses; `commitHash` is an optional short git SHA.", "type": "object", "additionalProperties": false, "required": ["projectName", "apiVersion", "checksum"], "properties": { "projectName": { "type": "string" }, "apiVersion": { "type": "string", "pattern": "^2\\.\\d+$", "description": "Major must be 2; any minor. Minors are additive-only (new optional fields only, never remove/rename/repurpose); a breaking change is a new major. See cc-json-2.0-format.md." }, "checksum": { "type": "string" }, "commitHash": { "type": "string" } } }, "FileNode": { "description": "A file or folder. `id` = first 16 hex of sha-256(canonical tree path). A File may not have children. `contentHash` is the optional per-file xxhash64.", "type": "object", "additionalProperties": false, "required": ["id", "name", "type"], "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "type": { "$ref": "#/definitions/NodeType" }, "children": { "type": "array", "items": { "$ref": "#/definitions/FileNode" } }, "contentHash": { "type": "string" }, "link": { "type": "string" } }, "if": { "properties": { "type": { "const": "File" } } }, "then": { "not": { "required": ["children"] } } }, "NodeType": { "enum": ["File", "Folder"], "type": "string" }, "Lenses": { "description": "Additive overlays joined to `files` by id. `metrics`, `dependency`, `clusters` and `domain` are concrete; `security` is reserved; any unknown top-level lens is preserved verbatim on round-trip (hence no additionalProperties:false here).", "type": "object", "properties": { "metrics": { "$ref": "#/definitions/MetricsLens" }, "dependency": { "$ref": "#/definitions/DependencyLens" }, "clusters": { "$ref": "#/definitions/ClustersLens" }, "domain": { "$ref": "#/definitions/DomainLens" }, "security": { "type": "object" } } }, "MetricsLens": { "description": "Per-node metrics, keyed by node id, plus their descriptors and types.", "type": "object", "additionalProperties": false, "properties": { "attributes": { "description": "Map of node id -> metric map (numeric or, for e.g. authors, list values).", "type": "object", "additionalProperties": { "type": "object" } }, "attributeDescriptors": { "type": "object", "additionalProperties": { "$ref": "#/definitions/AttributeDescriptor" } }, "attributeTypes": { "type": "object", "additionalProperties": { "enum": ["absolute", "relative"], "type": "string" } } } }, "DependencyLens": { "description": "The dependency graph in both of its projections. The physical one is `edges` between file nodes (by id) with their attribute types and descriptors, plus `nodes`, each node's place in that graph. The logical one is the graph as the code declares it: `leaves` are the declarations, grouped under the id of the file node they are declared in, `namespaces` the packages containing them, and `leafEdges` the dependencies between declarations. Every table is optional, so a file that carries only the physical projection omits the logical one and an unused lens slot stays `{}`.", "type": "object", "additionalProperties": false, "properties": { "edges": { "type": "array", "items": { "$ref": "#/definitions/Edge" } }, "nodes": { "description": "Map of node id -> that node's dependency-graph entry.", "type": "object", "additionalProperties": { "$ref": "#/definitions/DependencyNode" } }, "namespaces": { "description": "Map of declared package name -> that namespace's entry in the logical graph.", "type": "object", "additionalProperties": { "$ref": "#/definitions/DependencyNamespace" } }, "leaves": { "description": "Map of file node id -> the declarations of that file, each under a key that is unique within the file.", "type": "object", "additionalProperties": { "type": "object", "additionalProperties": { "$ref": "#/definitions/DependencyLeaf" } } }, "leafEdges": { "description": "The dependencies between declarations — the signal the file-collapsed `edges` cannot carry, because an edge between two declarations of one file disappears there.", "type": "array", "items": { "$ref": "#/definitions/LeafEdge" } }, "attributeDescriptors": { "type": "object", "additionalProperties": { "$ref": "#/definitions/AttributeDescriptor" } }, "attributeTypes": { "type": "object", "additionalProperties": { "enum": ["absolute", "relative"], "type": "string" } } } }, "Edge": { "description": "A dependency edge referencing its endpoints by node id. `isCyclic` and `isPointingUpwards` place the edge in the dependency graph; the four edge types (regular, cyclic, container-level feedback, leaf-level feedback) are a pure function of that pair and are derived, never stored.", "type": "object", "additionalProperties": false, "required": ["fromId", "toId"], "properties": { "fromId": { "type": "string" }, "toId": { "type": "string" }, "attributes": { "type": "object" }, "isCyclic": { "description": "Whether this edge takes part in a dependency cycle. Absent means false.", "type": "boolean" }, "isPointingUpwards": { "description": "Whether this edge runs against the levelized flow, i.e. its target sits at the same level as or above its source. Absent means false.", "type": "boolean" } } }, "DependencyNode": { "description": "One node's place in the dependency graph. An object rather than a bare level so per-node facts (declaration kind, detected language) can be added later without a breaking change.", "type": "object", "additionalProperties": false, "required": ["level"], "properties": { "level": { "description": "The node's levelization depth relative to its containing folder: 0 for a node that depends on nothing, n for one that depends only on nodes below level n.", "type": "integer", "minimum": 0 } } }, "DependencyNamespace": { "description": "One package's place in the logical dependency graph, keyed by its declared name. The key is never split: the containing package is `parent`.", "type": "object", "additionalProperties": false, "required": ["level"], "properties": { "parent": { "description": "Key of the containing namespace. Absent on a top-level namespace.", "type": "string" }, "level": { "description": "The namespace's levelization depth relative to its containing namespace, on the same scale as DependencyNode.level.", "type": "integer", "minimum": 0 } } }, "DependencyLeaf": { "description": "One declaration — a class, interface, function, ... — of one file. It is addressed by the id of its file node and its key within that file, so it needs no id of its own. A declaration split across files, such as a partial class, is one leaf per file with the same `namespace` and key.", "type": "object", "additionalProperties": false, "required": ["kind"], "properties": { "name": { "description": "The declaration's name. Absent when it equals the key.", "type": "string" }, "kind": { "description": "The kind of declaration. An open vocabulary; known values: class, valueclass, interface, annotation, enum, function, variable, reexport, script, unknown.", "type": "string" }, "language": { "description": "The language the declaration is written in, lower case.", "type": "string" }, "namespace": { "description": "Key of the namespace the declaration belongs to. Absent where the language has no packages apart from its files, and on a nested declaration, which inherits it through `parent`.", "type": "string" }, "parent": { "description": "Key of the declaration of the same file this one is nested in.", "type": "string" }, "level": { "description": "The declaration's levelization depth among its siblings. Absent when the producer skipped levelization.", "type": "integer", "minimum": 0 } } }, "LeafEdge": { "description": "A dependency between two declarations. `fromId` and `toId` are file node ids exactly as on an Edge; `fromLeaf` and `toLeaf` are the keys of the declarations within those files. A list of its own rather than a widened Edge, because `edges` is what the edge-metric machinery, `edgefilter` and the 3D map read.", "type": "object", "additionalProperties": false, "required": ["fromId", "fromLeaf", "toId", "toLeaf"], "properties": { "fromId": { "type": "string" }, "fromLeaf": { "type": "string" }, "toId": { "type": "string" }, "toLeaf": { "type": "string" }, "attributes": { "type": "object" }, "usage": { "description": "Every way the source declaration uses the target; folding two edges of one pair unions the ways rather than picking one. An open vocabulary; known values: usage, inheritance, implementation, instantiation, argument, return_value, constant_access.", "type": "array", "items": { "type": "string" } }, "isCyclic": { "description": "Whether this leaf edge takes part in a dependency cycle. Absent means false.", "type": "boolean" }, "isPointingUpwards": { "description": "Whether this leaf edge runs against the levelized flow of the logical graph. Absent means false.", "type": "boolean" } } }, "ClustersLens": { "description": "Named clusterings of nodes, joined to `files` by id. Structurally a cross-cutting relation like edges, not a per-node metric. Defined but not yet produced or visualized; see dev_docs/cc-json-2.0-clusters-lens.md.", "type": "object", "additionalProperties": false, "required": ["clusterings"], "properties": { "clusterings": { "description": "Map of clustering id -> clustering. A keyed map because clusterings merge by exactly one key, so JSON itself enforces id uniqueness.", "type": "object", "additionalProperties": { "$ref": "#/definitions/Clustering" } } } }, "Clustering": { "description": "One grouping of the nodes (author ownership, temporal coupling, feature scope, ...). A file may carry several orthogonal clusterings side by side; views activate one at a time, like the edge metric today.", "type": "object", "additionalProperties": false, "required": ["title", "membership", "analyzers", "clusters"], "properties": { "title": { "type": "string" }, "membership": { "description": "How a node may belong to clusters. `partition`: at most one cluster, weight implied 1. `weighted`: overlapping fractional membership; a node's weights across the clusters of this clustering must sum to at most 1 — a semantic invariant that JSON Schema cannot express, so it is not validated here. `overlay`: independent per-cluster membership; weights are per-cluster and never summed across clusters.", "enum": ["partition", "weighted", "overlay"], "type": "string" }, "weightBasis": { "description": "Names the metrics lens key the member weights are a fraction of (e.g. `rloc`, `loc`, `commits`), so views can weight aggregation with real per-node values.", "type": "string" }, "analyzers": { "description": "The producers that contributed to this clustering; merged by union.", "type": "array", "items": { "type": "string" } }, "clusters": { "description": "Producer-controlled display order; an array rather than a map because clusters are fuller records.", "type": "array", "items": { "$ref": "#/definitions/Cluster" } }, "attributeDescriptors": { "type": "object", "additionalProperties": { "$ref": "#/definitions/AttributeDescriptor" } }, "attributeTypes": { "type": "object", "additionalProperties": { "enum": ["absolute", "relative"], "type": "string" } } } }, "Cluster": { "description": "A single group of nodes within a clustering, carrying its own attributes (described by the clustering's descriptors and types). `parentId` forms an optional forest within the clustering; flat clusterings leave it null or omit it.", "type": "object", "additionalProperties": false, "required": ["id", "name", "members"], "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "parentId": { "type": ["string", "null"] }, "attributes": { "type": "object" }, "members": { "type": "array", "items": { "$ref": "#/definitions/ClusterMember" } } } }, "ClusterMember": { "description": "A node's membership in a cluster, referencing the node by id — the same join as edges. `weight` is the fraction of the clustering's `weightBasis` attributed to this cluster; omitted means 1.", "type": "object", "additionalProperties": false, "required": ["nodeId"], "properties": { "nodeId": { "type": "string" }, "weight": { "type": "number", "minimum": 0, "maximum": 1 } } }, "DomainLens": { "description": "Domain vocabulary extracted from the source. `nodes` maps a node id to that node's entry; lens-wide data (corpus weights, producer provenance) belongs beside `nodes`, never inside it. `nodes` is optional so an unused lens slot stays `{}` — the form `carriesData()` treats as carrying nothing, like `security`.", "type": "object", "additionalProperties": false, "properties": { "nodes": { "description": "Map of node id -> that node's domain entry.", "type": "object", "additionalProperties": { "$ref": "#/definitions/DomainNode" } } } }, "DomainNode": { "description": "One node's domain entry. An object rather than a bare word array so per-node facts (dominant term, token count, detected language) can be added later without a breaking change.", "type": "object", "additionalProperties": false, "required": ["words"], "properties": { "words": { "description": "The node's word bank, in producer-controlled order.", "type": "array", "items": { "$ref": "#/definitions/DomainWord" } } } }, "DomainWord": { "description": "One extracted domain term for a node. `frequency` is the raw occurrence count; `tfidf` is the optional corpus-relative weight.", "type": "object", "additionalProperties": false, "required": ["text", "frequency"], "properties": { "text": { "type": "string" }, "frequency": { "type": "number" }, "tfidf": { "type": "number" } } }, "AttributeDescriptor": { "description": "Human-facing metadata for a metric/edge attribute.", "type": "object", "additionalProperties": false, "properties": { "title": { "type": "string" }, "description": { "type": "string" }, "hintLowValue": { "type": "string" }, "hintHighValue": { "type": "string" }, "link": { "type": "string" }, "direction": { "type": "number" }, "analyzers": { "type": "array", "items": { "type": "string" } } } } } }