@conform-ed/contracts 0.0.3
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/.turbo/turbo-build.log +2 -0
- package/.turbo/turbo-format.log +6 -0
- package/.turbo/turbo-lint.log +4 -0
- package/.turbo/turbo-test.log +196 -0
- package/.turbo/turbo-typecheck.log +2 -0
- package/README.md +52 -0
- package/caliper-v1_2-zod-templates.md +123 -0
- package/case-v1_1-zod-templates.md +290 -0
- package/cat-v1_0-zod-templates.md +73 -0
- package/cc-v1_3-zod-templates.md +531 -0
- package/cc-v1_4-zod-templates.md +247 -0
- package/clr-v2_0-zod-templates.md +117 -0
- package/cmi5-v1_0-zod-templates.md +9 -0
- package/lti-zod-templates.md +11 -0
- package/oneroster-v1_2-zod-templates.md +76 -0
- package/open-badges-v3_0-zod-templates.md +66 -0
- package/package.json +42 -0
- package/qti-v2_1-zod-templates.md +45 -0
- package/qti-v2_2-zod-templates.md +32 -0
- package/qti-v3_0_1-zod-templates.md +421 -0
- package/src/adapter.ts +83 -0
- package/src/caliper/v1_2/caliper_v1p2_bootcamp_schema.ts +781 -0
- package/src/caliper/v1_2/index.ts +37 -0
- package/src/caliper/v1_2/shared.ts +122 -0
- package/src/caliper/v1_2/textual_requirements.ts +219 -0
- package/src/case/v1_1/case_v1p1_cfassociation_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cfassociationgrouping_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cfassociationset_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cfconceptset_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cfdocument_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cfdocumentset_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cfitem_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cfitemtypeset_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cflicense_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cfpackage_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cfrubric_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_cfsubjectset_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_imsx_statusinfo_jsonschema1.ts +1 -0
- package/src/case/v1_1/case_v1p1_openapi3_restbinding_schema.ts +113 -0
- package/src/case/v1_1/index.ts +95 -0
- package/src/case/v1_1/shared.ts +384 -0
- package/src/cat/v1_0/cat_v1p0_restbinding_operations_schema.ts +75 -0
- package/src/cat/v1_0/index.ts +124 -0
- package/src/cat/v1_0/shared.ts +345 -0
- package/src/clr/v2_0/clr_v2p0_achievementcredential_schema.ts +16 -0
- package/src/clr/v2_0/clr_v2p0_clrcredential_schema.ts +9 -0
- package/src/clr/v2_0/clr_v2p0_endorsementcredential_schema.ts +11 -0
- package/src/clr/v2_0/clr_v2p0_getclrcredentialsresponse_schema.ts +1 -0
- package/src/clr/v2_0/clr_v2p0_imsx_statusinfo_schema.ts +8 -0
- package/src/clr/v2_0/clr_v2p0_profile_schema.ts +9 -0
- package/src/clr/v2_0/index.ts +22 -0
- package/src/clr/v2_0/shared.ts +206 -0
- package/src/cmi5/index.ts +3 -0
- package/src/cmi5/v1_0/index.ts +134 -0
- package/src/common-cartridge/v1_3/ccv1p3_imsccauth_v1p3.ts +26 -0
- package/src/common-cartridge/v1_3/ccv1p3_imscp_v1p2_v1p0.ts +352 -0
- package/src/common-cartridge/v1_3/ccv1p3_imscsmd_v1p0.ts +35 -0
- package/src/common-cartridge/v1_3/ccv1p3_imsdt_v1p3.ts +33 -0
- package/src/common-cartridge/v1_3/ccv1p3_imswl_v1p3.ts +23 -0
- package/src/common-cartridge/v1_3/ccv1p3_lomccltilink_v1p0.ts +14 -0
- package/src/common-cartridge/v1_3/ccv1p3_lommanifest_v1p0.ts +14 -0
- package/src/common-cartridge/v1_3/ccv1p3_lomresource_v1p0.ts +14 -0
- package/src/common-cartridge/v1_3/ccv1p3_qtiasiv1p2p1_v1p0.ts +964 -0
- package/src/common-cartridge/v1_3/index.ts +41 -0
- package/src/common-cartridge/v1_3/lom-internal.ts +396 -0
- package/src/common-cartridge/v1_3/shared.ts +68 -0
- package/src/common-cartridge/v1_4/core/ccv1p4_imscp_v1p2_v1p0.ts +360 -0
- package/src/common-cartridge/v1_4/core/ccv1p4_lommanifest_v1p0.ts +14 -0
- package/src/common-cartridge/v1_4/core/ccv1p4_lomresource_v1p0.ts +14 -0
- package/src/common-cartridge/v1_4/extension/cc_extresource_assignmentv1p0_v1p0.ts +61 -0
- package/src/common-cartridge/v1_4/extension/ccv1p4_cpextensionv1p2_v1p0.ts +20 -0
- package/src/common-cartridge/v1_4/extension/ims_openvideov1p0_v1p0.ts +325 -0
- package/src/common-cartridge/v1_4/index.ts +104 -0
- package/src/common-cartridge/v1_4/k12/ccv1p4_imscp_v1p2_v1p0.ts +19 -0
- package/src/common-cartridge/v1_4/k12/ccv1p4_imscp_v1p2_v1p0_thin.ts +17 -0
- package/src/common-cartridge/v1_4/k12/ccv1p4_lommanifest_v1p0.ts +14 -0
- package/src/common-cartridge/v1_4/k12/ccv1p4_lomresource_v1p0.ts +14 -0
- package/src/common-cartridge/v1_4/lom-internal.ts +476 -0
- package/src/common-cartridge/v1_4/shared/ccv1p4_imsccauth_v1p4.ts +26 -0
- package/src/common-cartridge/v1_4/shared/ccv1p4_imscsmd_v1p1.ts +36 -0
- package/src/common-cartridge/v1_4/shared/ccv1p4_imsdt_v1p4.ts +33 -0
- package/src/common-cartridge/v1_4/shared/ccv1p4_imslticc_v1p4.ts +45 -0
- package/src/common-cartridge/v1_4/shared/ccv1p4_imswl_v1p4.ts +23 -0
- package/src/common-cartridge/v1_4/shared/ccv1p4_lomccltilink_v1p0.ts +14 -0
- package/src/common-cartridge/v1_4/shared/ccv1p4_qtiasiv1p2p1_v1p0.ts +964 -0
- package/src/common-cartridge/v1_4/shared/imsbasiclti_v1p0p1.ts +24 -0
- package/src/common-cartridge/v1_4/shared/imslticm_v1p0.ts +23 -0
- package/src/common-cartridge/v1_4/shared/imslticp_v1p0.ts +57 -0
- package/src/common-cartridge/v1_4/shared/lineitem_v1p0.ts +35 -0
- package/src/common-cartridge/v1_4/shared/resourcea11ymetadata-20210915.ts +110 -0
- package/src/common-cartridge/v1_4/shared.ts +68 -0
- package/src/common-cartridge/v1_4/thin/ccv1p4_imscp_v1p2_v1p0.ts +243 -0
- package/src/common-cartridge/v1_4/thin/ccv1p4_lommanifest_v1p0.ts +14 -0
- package/src/common-cartridge/v1_4/thin/ccv1p4_lomresource_v1p0.ts +14 -0
- package/src/common-cartridge/v1_4/vdex/imsmd_loose_v1p3p2.ts +13 -0
- package/src/common-cartridge/v1_4/vdex/imsvdex_v1p0.ts +124 -0
- package/src/config.ts +121 -0
- package/src/index.ts +32 -0
- package/src/lti/ags/v2_0/index.ts +97 -0
- package/src/lti/deep-linking/v2_0/index.ts +100 -0
- package/src/lti/index.ts +26 -0
- package/src/lti/nrps/v2_0/index.ts +69 -0
- package/src/lti/proctoring/v1_0/index.ts +131 -0
- package/src/lti/shared.ts +66 -0
- package/src/lti/v1_3/index.ts +84 -0
- package/src/oneroster/v1_2/index.ts +156 -0
- package/src/oneroster/v1_2/or_v1p2_csv_binding_schema.ts +427 -0
- package/src/oneroster/v1_2/or_v1p2_gradebook_restbinding_schema.ts +120 -0
- package/src/oneroster/v1_2/or_v1p2_gradebook_service_schema.ts +243 -0
- package/src/oneroster/v1_2/or_v1p2_resource_restbinding_schema.ts +24 -0
- package/src/oneroster/v1_2/or_v1p2_resource_service_schema.ts +47 -0
- package/src/oneroster/v1_2/or_v1p2_rostering_restbinding_schema.ts +84 -0
- package/src/oneroster/v1_2/or_v1p2_rostering_service_schema.ts +288 -0
- package/src/oneroster/v1_2/shared.ts +90 -0
- package/src/open-badges/v3_0/index.ts +20 -0
- package/src/open-badges/v3_0/ob_v3p0_achievementcredential_schema.ts +17 -0
- package/src/open-badges/v3_0/ob_v3p0_endorsementcredential_schema.ts +11 -0
- package/src/open-badges/v3_0/ob_v3p0_getopenbadgecredentialsresponse_schema.ts +1 -0
- package/src/open-badges/v3_0/ob_v3p0_imsx_statusinfo_schema.ts +8 -0
- package/src/open-badges/v3_0/ob_v3p0_profile_schema.ts +9 -0
- package/src/open-badges/v3_0/shared.ts +458 -0
- package/src/qti/v2-internal.ts +1683 -0
- package/src/qti/v2_1/apipv1p0_qtiextv2p1_v1p0.ts +3 -0
- package/src/qti/v2_1/imsqti_metadata_v2p1.ts +3 -0
- package/src/qti/v2_1/imsqti_result_v2p1.ts +3 -0
- package/src/qti/v2_1/imsqti_usagedata_v2p1.ts +3 -0
- package/src/qti/v2_1/imsqti_v2p1p2.ts +71 -0
- package/src/qti/v2_1/index.ts +53 -0
- package/src/qti/v2_1/qtiv2p1_imscpv1p2_v1p0.ts +3 -0
- package/src/qti/v2_1/schemas.ts +15 -0
- package/src/qti/v2_1/shared.ts +3 -0
- package/src/qti/v2_2/apipv1p0_qtiextv2p2_v1p0p1.ts +3 -0
- package/src/qti/v2_2/imsqti_metadata_v2p2.ts +3 -0
- package/src/qti/v2_2/imsqti_result_v2p2.ts +3 -0
- package/src/qti/v2_2/imsqti_usagedata_v2p2.ts +3 -0
- package/src/qti/v2_2/imsqti_v2p2p4.ts +76 -0
- package/src/qti/v2_2/imsqtiv2p2p4_html5_v1p0.ts +8 -0
- package/src/qti/v2_2/index.ts +59 -0
- package/src/qti/v2_2/qtiv2p2_csm_v2p2.ts +4 -0
- package/src/qti/v2_2/qtiv2p2_imscpv1p2_v1p0.ts +3 -0
- package/src/qti/v2_2/schemas.ts +19 -0
- package/src/qti/v2_2/shared.ts +3 -0
- package/src/qti/v3_0_1/assessment-internal.ts +1509 -0
- package/src/qti/v3_0_1/imsqti_asiv3p0p1_v1p0.ts +57 -0
- package/src/qti/v3_0_1/imsqti_itemv3p0p1_v1p0.ts +60 -0
- package/src/qti/v3_0_1/imsqti_metadatav3p0_v1p0.ts +73 -0
- package/src/qti/v3_0_1/imsqti_outcomev3p0p1_v1p0.ts +11 -0
- package/src/qti/v3_0_1/imsqti_responseprocessingv3p0p1_v1p0.ts +17 -0
- package/src/qti/v3_0_1/imsqti_resultv3p0_v1p0.ts +222 -0
- package/src/qti/v3_0_1/imsqti_sectionv3p0p1_v1p0.ts +15 -0
- package/src/qti/v3_0_1/imsqti_stimulusv3p0p1_v1p0.ts +15 -0
- package/src/qti/v3_0_1/imsqti_testv3p0p1_v1p0.ts +49 -0
- package/src/qti/v3_0_1/imsqti_usagedatav3p0_v1p0.ts +77 -0
- package/src/qti/v3_0_1/imsqtiv3p0_afa3p0pnp_v1p0.ts +269 -0
- package/src/qti/v3_0_1/index.ts +50 -0
- package/src/qti/v3_0_1/processing-internal.ts +667 -0
- package/src/qti/v3_0_1/shared.ts +146 -0
- package/src/qti/v3_0_1/variables-internal.ts +274 -0
- package/src/shared/imsx-status.ts +49 -0
- package/src/summary.ts +70 -0
- package/src/vc-data-model/v2_0/index.ts +27 -0
- package/src/vc-data-model/v2_0/shared.ts +206 -0
- package/src/xapi/index.ts +12 -0
- package/src/xapi/shared.ts +444 -0
- package/src/xapi/v1_0_3/index.ts +169 -0
- package/src/xapi/v2_0/index.ts +256 -0
- package/test/caliper-v1_2.test.ts +270 -0
- package/test/case-v1_1.test.ts +147 -0
- package/test/cat-v1_0.test.ts +338 -0
- package/test/cc-v1_4.test.ts +239 -0
- package/test/clr-v2_0.test.ts +225 -0
- package/test/cmi5-v1_0.test.ts +196 -0
- package/test/contracts.test.ts +125 -0
- package/test/fixtures/cmi5/extended-cmi5.xml +72 -0
- package/test/fixtures/cmi5/simple-cmi5.xml +26 -0
- package/test/lti.test.ts +146 -0
- package/test/oneroster-v1_2.test.ts +234 -0
- package/test/open-badges-v3_0.test.ts +144 -0
- package/test/qti-v2_1.test.ts +146 -0
- package/test/qti-v2_2.test.ts +154 -0
- package/test/qti-v3_0_1.test.ts +576 -0
- package/test/schema-examples.test.ts +101 -0
- package/test/vc-data-model-v2_0.test.ts +63 -0
- package/test/xapi.test.ts +384 -0
- package/tsconfig.json +7 -0
- package/vc-data-model-v2_0-zod-templates.md +43 -0
- package/xapi-zod-templates.md +95 -0
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
# Common Cartridge XSD bundle (including embedded QTI profiles) → Zod template notes
|
|
2
|
+
|
|
3
|
+
## Published specification
|
|
4
|
+
|
|
5
|
+
- Overview: `https://www.imsglobal.org/cc/ccv1p3/imscc_Overview-v1p3.html`
|
|
6
|
+
|
|
7
|
+
This note accompanies the split source under `packages/contracts/src/common-cartridge/v1_3/` and the version barrel `packages/contracts/src/common-cartridge/v1_3/index.ts`.
|
|
8
|
+
|
|
9
|
+
The TypeScript templates are now split primarily by source XSD file. This document explains the design decisions, the tradeoffs behind them, and the places where the XSDs are not sufficient on their own because the real constraints live in embedded Schematron rules or in profile prose.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 1. What was analyzed
|
|
14
|
+
|
|
15
|
+
The templates are based on these local XSD files under `tmp/cc`:
|
|
16
|
+
|
|
17
|
+
- `ccv1p3_imscp_v1p2_v1p0.xsd`
|
|
18
|
+
- `ccv1p3_imscsmd_v1p0.xsd`
|
|
19
|
+
- `ccv1p3_imsdt_v1p3.xsd`
|
|
20
|
+
- `ccv1p3_imswl_v1p3.xsd`
|
|
21
|
+
- `ccv1p3_lomccltilink_v1p0.xsd`
|
|
22
|
+
- `ccv1p3_lommanifest_v1p0.xsd`
|
|
23
|
+
- `ccv1p3_lomresource_v1p0.xsd`
|
|
24
|
+
- `ccv1p3_qtiasiv1p2p1_v1p0.xsd`
|
|
25
|
+
- `ccv1p3_imsccauth_v1p3.xsd`
|
|
26
|
+
|
|
27
|
+
This directory is best understood as a **Common Cartridge schema bundle**, not a separate QTI directory. One of the files (`ccv1p3_qtiasiv1p2p1_v1p0.xsd`) is the embedded Common Cartridge profile of QTI 1.2.1, but it belongs to this Common Cartridge family of schemas.
|
|
28
|
+
|
|
29
|
+
The Common Cartridge manifest XSD imports the authorization schema `ccv1p3_imsccauth_v1p3.xsd`, which is now modeled directly. That lets the templates represent both the optional manifest-level `authorizations` element and the imported resource-level `protected` boolean attribute.
|
|
30
|
+
|
|
31
|
+
Implementation layout:
|
|
32
|
+
|
|
33
|
+
- one TypeScript module per source XSD under `src/common-cartridge/v1_3/`
|
|
34
|
+
- a small number of internal support modules for shared helpers and LOM profile generation
|
|
35
|
+
- a version barrel at `src/common-cartridge/v1_3/index.ts`
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2. The biggest design decision: raw XML fidelity vs useful TypeScript shapes
|
|
40
|
+
|
|
41
|
+
### Problem
|
|
42
|
+
|
|
43
|
+
XSD is fundamentally an XML grammar. Zod validates JavaScript values. There is no single “correct” way to project XML/XSD into JS objects.
|
|
44
|
+
|
|
45
|
+
Some examples from these schemas:
|
|
46
|
+
|
|
47
|
+
- XML attributes like `xml:lang`, `xml:base`, `linkrefid`, `feedbacktype`
|
|
48
|
+
- simple-content elements that carry both text and attributes
|
|
49
|
+
- embedded QTI-profile nodes whose meaning depends on **ordered heterogeneous children**
|
|
50
|
+
- LOM nodes whose XSD uses repeated unordered `xs:choice`, with the real cardinality enforced in embedded Schematron
|
|
51
|
+
|
|
52
|
+
If the goal were exact round-tripping, the right model would look like a generic XML tree.
|
|
53
|
+
If the goal were practical validation in TypeScript, the right model is a normalized object model.
|
|
54
|
+
|
|
55
|
+
### Decision
|
|
56
|
+
|
|
57
|
+
The templates deliberately target a **normalized parsed-XML representation**:
|
|
58
|
+
|
|
59
|
+
- element text is represented as `value`
|
|
60
|
+
- attributes are flattened to JS properties
|
|
61
|
+
- imported namespace prefixes are normalized away when context already disambiguates them
|
|
62
|
+
- embedded QTI-profile ordered children are preserved with `children: Node[]` unions where necessary
|
|
63
|
+
- LOM is normalized into plain object properties and arrays instead of preserving arbitrary sibling order
|
|
64
|
+
|
|
65
|
+
### Rationale
|
|
66
|
+
|
|
67
|
+
This choice makes the schemas usable.
|
|
68
|
+
|
|
69
|
+
A perfectly XML-faithful model would technically be more complete, but it would also be so generic that the resulting Zod templates would say very little about the real domain structure. The current templates are intentionally opinionated in favor of developer usability.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## 3. Why the templates use “raw” and “profile” layers
|
|
74
|
+
|
|
75
|
+
A recurring pattern across these XSDs is that the literal XSD body is **not the whole story**.
|
|
76
|
+
|
|
77
|
+
Two important examples:
|
|
78
|
+
|
|
79
|
+
1. **Common Cartridge manifest**
|
|
80
|
+
- the XSD defines the structural grammar
|
|
81
|
+
- the embedded Schematron defines many real business rules
|
|
82
|
+
- duplicate dependency/file detection
|
|
83
|
+
- forbidden dependency graphs between resource types
|
|
84
|
+
- `href`/`file` coupling
|
|
85
|
+
- item-to-question-bank restrictions
|
|
86
|
+
|
|
87
|
+
2. **Embedded QTI ASI profile inside Common Cartridge**
|
|
88
|
+
- the XSD allows broad structural patterns
|
|
89
|
+
- the embedded Schematron narrows them into actual question profile rules
|
|
90
|
+
- T/F, multiple choice, multiple response, FIB, pattern match, essay
|
|
91
|
+
- metadata field vocabularies and multiplicities
|
|
92
|
+
- feedback linkage rules
|
|
93
|
+
|
|
94
|
+
### Decision
|
|
95
|
+
|
|
96
|
+
The TypeScript file exports both:
|
|
97
|
+
|
|
98
|
+
- **raw structural schemas** that match the XSD-declared object shape
|
|
99
|
+
- **profile schemas** with `.superRefine()` rules to encode the most important Schematron-level constraints
|
|
100
|
+
|
|
101
|
+
### Rationale
|
|
102
|
+
|
|
103
|
+
This makes the output reusable in two modes:
|
|
104
|
+
|
|
105
|
+
- validate “is this shaped like the XML grammar?”
|
|
106
|
+
- validate “does this satisfy the actual profile semantics the XSD expects?”
|
|
107
|
+
|
|
108
|
+
That split is especially important because the profile prose, the XSD, and the active embedded Schematron do not always agree perfectly.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## 4. File-by-file analysis and mapping decisions
|
|
113
|
+
|
|
114
|
+
## 4.1 `ccv1p3_imscsmd_v1p0.xsd`
|
|
115
|
+
|
|
116
|
+
This is the simplest schema in the set.
|
|
117
|
+
|
|
118
|
+
### Structural summary
|
|
119
|
+
|
|
120
|
+
Root element:
|
|
121
|
+
|
|
122
|
+
- `curriculumStandardsMetadataSet`
|
|
123
|
+
|
|
124
|
+
Important types:
|
|
125
|
+
|
|
126
|
+
- `CurriculumStandardsMetadataSet.Type`
|
|
127
|
+
- `CurriculumStandardsMetadata.Type`
|
|
128
|
+
- `SetOfGUIDs.Type`
|
|
129
|
+
- `LabelledGUID.Type`
|
|
130
|
+
|
|
131
|
+
### Mapping decision
|
|
132
|
+
|
|
133
|
+
This XSD maps very directly to plain objects, so the template stays close to the XSD names.
|
|
134
|
+
|
|
135
|
+
### Rationale
|
|
136
|
+
|
|
137
|
+
There are no difficult ordering or namespace tradeoffs here, so a straightforward direct Zod object model is the most transparent choice.
|
|
138
|
+
|
|
139
|
+
---
|
|
140
|
+
|
|
141
|
+
## 4.2 `ccv1p3_imsdt_v1p3.xsd`
|
|
142
|
+
|
|
143
|
+
Discussion Topic is also structurally straightforward.
|
|
144
|
+
|
|
145
|
+
### Structural summary
|
|
146
|
+
|
|
147
|
+
Root element:
|
|
148
|
+
|
|
149
|
+
- `topic`
|
|
150
|
+
|
|
151
|
+
Important types:
|
|
152
|
+
|
|
153
|
+
- `Topic.Type`
|
|
154
|
+
- `Text.Type`
|
|
155
|
+
- `Attachments.Type`
|
|
156
|
+
- `Attachment.Type`
|
|
157
|
+
|
|
158
|
+
### Mapping decision
|
|
159
|
+
|
|
160
|
+
- `text` becomes an object with `value` and `texttype`
|
|
161
|
+
- `attachment` becomes an object with `href`
|
|
162
|
+
- the `grpStrict.any` extension point becomes `extensions?: XmlExtensionNode[]`
|
|
163
|
+
|
|
164
|
+
### Rationale
|
|
165
|
+
|
|
166
|
+
This keeps the schema readable while still preserving the important information from the XSD:
|
|
167
|
+
|
|
168
|
+
- text value
|
|
169
|
+
- MIME-style text type
|
|
170
|
+
- extension slot
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
## 4.3 `ccv1p3_imswl_v1p3.xsd`
|
|
175
|
+
|
|
176
|
+
Web Link is similar to Discussion Topic.
|
|
177
|
+
|
|
178
|
+
### Structural summary
|
|
179
|
+
|
|
180
|
+
Root element:
|
|
181
|
+
|
|
182
|
+
- `webLink`
|
|
183
|
+
|
|
184
|
+
Important types:
|
|
185
|
+
|
|
186
|
+
- `WebLink.Type`
|
|
187
|
+
- `URL.Type`
|
|
188
|
+
|
|
189
|
+
### Mapping decision
|
|
190
|
+
|
|
191
|
+
- `url` is modeled as a nested object with `href`, `target`, and `windowFeatures`
|
|
192
|
+
- extension points again become `extensions?: XmlExtensionNode[]`
|
|
193
|
+
|
|
194
|
+
### Rationale
|
|
195
|
+
|
|
196
|
+
This is the cleanest normalized JS shape while still remaining very easy to map back to the source XSD.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 4.4 `ccv1p3_lommanifest_v1p0.xsd` and `ccv1p3_lomresource_v1p0.xsd`
|
|
201
|
+
|
|
202
|
+
These two schemas are effectively the same structurally.
|
|
203
|
+
|
|
204
|
+
### Structural summary
|
|
205
|
+
|
|
206
|
+
Both expose:
|
|
207
|
+
|
|
208
|
+
- root element `lom`
|
|
209
|
+
- the same large set of LOM complex types
|
|
210
|
+
- loose value typing for vocab-like `value` elements
|
|
211
|
+
- `grpLax.any` extension points and foreign attributes on many types
|
|
212
|
+
|
|
213
|
+
### Important XSD characteristic
|
|
214
|
+
|
|
215
|
+
These schemas use repeated unordered `xs:choice` content models. The **real singleton limits** are enforced by the embedded Schematron rules.
|
|
216
|
+
|
|
217
|
+
Example:
|
|
218
|
+
|
|
219
|
+
- `general.title` is intended to be 0..1
|
|
220
|
+
- `rights.cost` is intended to be 0..1
|
|
221
|
+
- `relation.kind` is intended to be 0..1
|
|
222
|
+
|
|
223
|
+
but the raw XSD shape on its own is looser than that.
|
|
224
|
+
|
|
225
|
+
### Mapping decision
|
|
226
|
+
|
|
227
|
+
The templates use:
|
|
228
|
+
|
|
229
|
+
- plain object properties for singleton-ish children
|
|
230
|
+
- arrays for repeatable children
|
|
231
|
+
- optional `extensions` / `foreignAttributes` on loose profiles
|
|
232
|
+
- a small Schematron-inspired refinement on the root LOM object to document the singleton expectation
|
|
233
|
+
|
|
234
|
+
### Rationale
|
|
235
|
+
|
|
236
|
+
Trying to preserve the unordered repeated `xs:choice` literally in JS would produce an awkward structure that is much less usable than a normalized object model. This is a case where Zod is better used to validate the **intended object model** rather than to mirror the low-level serialization trick the XSD uses.
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 4.5 `ccv1p3_lomccltilink_v1p0.xsd`
|
|
241
|
+
|
|
242
|
+
This is the strictest of the LOM family.
|
|
243
|
+
|
|
244
|
+
### Structural summary
|
|
245
|
+
|
|
246
|
+
It shares the same high-level LOM section graph as the other LOM profiles, but it differs in two important ways:
|
|
247
|
+
|
|
248
|
+
1. it does **not** allow the loose extension model
|
|
249
|
+
2. many `value` elements are restricted to explicit enumerations
|
|
250
|
+
|
|
251
|
+
### Mapping decision
|
|
252
|
+
|
|
253
|
+
The TypeScript file reuses the same LOM section structure but swaps in strict value enums for the LTI profile.
|
|
254
|
+
|
|
255
|
+
### Rationale
|
|
256
|
+
|
|
257
|
+
This is a good place to share structure and vary only the profile policy:
|
|
258
|
+
|
|
259
|
+
- loose manifest/resource profiles: `value: z.string()`
|
|
260
|
+
- strict LTI profile: `value: z.enum([...])`
|
|
261
|
+
|
|
262
|
+
That keeps the templates internally consistent and makes the profile difference explicit.
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
## 4.6 `ccv1p3_imscp_v1p2_v1p0.xsd`
|
|
267
|
+
|
|
268
|
+
This is the Common Cartridge manifest profile.
|
|
269
|
+
|
|
270
|
+
### Structural summary
|
|
271
|
+
|
|
272
|
+
Root element:
|
|
273
|
+
|
|
274
|
+
- `manifest`
|
|
275
|
+
|
|
276
|
+
Key containers:
|
|
277
|
+
|
|
278
|
+
- `metadata`
|
|
279
|
+
- `organizations`
|
|
280
|
+
- `resources`
|
|
281
|
+
- optional imported `authorizations`
|
|
282
|
+
|
|
283
|
+
Key nested types:
|
|
284
|
+
|
|
285
|
+
- `Manifest.Type`
|
|
286
|
+
- `ManifestMetadata.Type`
|
|
287
|
+
- `Organization.Type`
|
|
288
|
+
- `ItemOrg.Type`
|
|
289
|
+
- `Item.Type`
|
|
290
|
+
- `Resource.Type`
|
|
291
|
+
- `ResourceMetadata.Type`
|
|
292
|
+
- `File.Type`
|
|
293
|
+
- `Dependency.Type`
|
|
294
|
+
- imported `Authorizations.Type`
|
|
295
|
+
- imported `Authorization.Type`
|
|
296
|
+
|
|
297
|
+
### Important tradeoff
|
|
298
|
+
|
|
299
|
+
The XSD itself is not enough. The embedded Schematron contributes a large amount of real semantic validation.
|
|
300
|
+
|
|
301
|
+
Examples encoded into the profile schema:
|
|
302
|
+
|
|
303
|
+
- duplicate `file/@href` inside a resource is forbidden
|
|
304
|
+
- duplicate `dependency/@identifierref` inside a resource is forbidden
|
|
305
|
+
- circular dependency on self is forbidden
|
|
306
|
+
- certain resource types must not use `href`
|
|
307
|
+
- `resource/@href` requires at least one matching `file/@href`
|
|
308
|
+
- web links must not have any dependency elements
|
|
309
|
+
- question-bank resources must not be referenced by manifest items
|
|
310
|
+
- manifest items with `identifierref` must not have child items
|
|
311
|
+
|
|
312
|
+
### Important modeling decision
|
|
313
|
+
|
|
314
|
+
The imported authorization schema is now modeled directly.
|
|
315
|
+
|
|
316
|
+
That adds explicit support for:
|
|
317
|
+
|
|
318
|
+
- manifest-level `authorizations`
|
|
319
|
+
- the nested `authorization` object with required `cartridgeId` and optional `webservice`
|
|
320
|
+
- required `access` values of `cartridge | resource`
|
|
321
|
+
- optional boolean `import` on the `authorizations` wrapper
|
|
322
|
+
- the imported resource-level `protected` boolean attribute
|
|
323
|
+
- the strict foreign-extension slot allowed by the auth XSD on `authorizations`
|
|
324
|
+
|
|
325
|
+
### Rationale
|
|
326
|
+
|
|
327
|
+
Now that the dependency is present locally, a direct schema mapping is more accurate than a placeholder. The templates still stop at **metadata structure validation**; they do not attempt to implement any authorization runtime or content-protection workflow.
|
|
328
|
+
|
|
329
|
+
---
|
|
330
|
+
|
|
331
|
+
## 4.7 `ccv1p3_qtiasiv1p2p1_v1p0.xsd`
|
|
332
|
+
|
|
333
|
+
This is the embedded Common Cartridge profile of QTI 1.2.1, and it is the most complex schema in the set.
|
|
334
|
+
|
|
335
|
+
### Structural summary
|
|
336
|
+
|
|
337
|
+
Root element:
|
|
338
|
+
|
|
339
|
+
- `questestinterop`
|
|
340
|
+
|
|
341
|
+
The root contains exactly one of:
|
|
342
|
+
|
|
343
|
+
- `assessment`
|
|
344
|
+
- `objectbank`
|
|
345
|
+
|
|
346
|
+
Key subtrees:
|
|
347
|
+
|
|
348
|
+
- item presentation
|
|
349
|
+
- response processing
|
|
350
|
+
- metadata fields
|
|
351
|
+
- feedback / hint / solution blocks
|
|
352
|
+
- recursive boolean condition nodes
|
|
353
|
+
- recursive flow / material / label nodes
|
|
354
|
+
|
|
355
|
+
### Biggest tradeoff in the whole set
|
|
356
|
+
|
|
357
|
+
QTI uses a lot of **ordered heterogeneous content**.
|
|
358
|
+
|
|
359
|
+
Examples:
|
|
360
|
+
|
|
361
|
+
- `flow`
|
|
362
|
+
- `flow_mat`
|
|
363
|
+
- `flow_label`
|
|
364
|
+
- `material`
|
|
365
|
+
- `render_choice`
|
|
366
|
+
- `render_fib`
|
|
367
|
+
- `itemfeedback`
|
|
368
|
+
|
|
369
|
+
If those are flattened into “just arrays of materials” or “just arrays of responses”, too much meaning is lost.
|
|
370
|
+
|
|
371
|
+
### Mapping decision
|
|
372
|
+
|
|
373
|
+
The templates model these QTI sections as small AST-like unions with explicit `kind` fields and ordered `children` arrays.
|
|
374
|
+
|
|
375
|
+
Examples:
|
|
376
|
+
|
|
377
|
+
- `material` → ordered array of `mattext | matref | matbreak`
|
|
378
|
+
- `flow` → ordered array of `flow | material | material_ref | response_lid | response_str`
|
|
379
|
+
- `itemfeedback` → ordered array of `flow_mat | material | solution | hint`
|
|
380
|
+
|
|
381
|
+
### Rationale
|
|
382
|
+
|
|
383
|
+
This is the smallest normalized JS representation that still preserves the aspects of order that matter for QTI logic and rendering.
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
## 5. Why `kind` discriminators were added for QTI nodes
|
|
388
|
+
|
|
389
|
+
The XSD obviously does not contain a `kind` attribute on most nodes.
|
|
390
|
+
|
|
391
|
+
### Decision
|
|
392
|
+
|
|
393
|
+
The templates add a synthetic `kind` literal field on many QTI node types.
|
|
394
|
+
|
|
395
|
+
Examples:
|
|
396
|
+
|
|
397
|
+
- `kind: "material"`
|
|
398
|
+
- `kind: "flow"`
|
|
399
|
+
- `kind: "response_label"`
|
|
400
|
+
- `kind: "hint"`
|
|
401
|
+
- `kind: "solution"`
|
|
402
|
+
|
|
403
|
+
### Rationale
|
|
404
|
+
|
|
405
|
+
This is one of the places where a TypeScript/Zod model is different from the source XML model on purpose.
|
|
406
|
+
|
|
407
|
+
Without a discriminator, recursive Zod unions become much harder to understand and to use downstream. Adding `kind` is a pragmatic normalization step that makes the schemas substantially more usable while still remaining structurally faithful.
|
|
408
|
+
|
|
409
|
+
---
|
|
410
|
+
|
|
411
|
+
## 6. Important places where the templates intentionally follow the XSD + active Schematron over prose
|
|
412
|
+
|
|
413
|
+
There are several mismatches between comments/prose and the literal schema bodies.
|
|
414
|
+
|
|
415
|
+
### Common Cartridge manifest examples
|
|
416
|
+
|
|
417
|
+
- the prose says `dependency/@identifierref` was changed to `xs:IDREF`, but the XSD body still declares `xs:string`
|
|
418
|
+
- the prose discusses external VDEX handling for resource types, but the XSD body still has a local inline enumeration
|
|
419
|
+
- the prose implies tighter constraints in some places than the active Schematron actually enforces
|
|
420
|
+
|
|
421
|
+
### QTI examples
|
|
422
|
+
|
|
423
|
+
- the profile prose strongly suggests some metadata containers are mandatory
|
|
424
|
+
- the raw XSD leaves them optional
|
|
425
|
+
- the active Schematron generally validates them **if present**, rather than forcing them to exist everywhere
|
|
426
|
+
|
|
427
|
+
### Decision
|
|
428
|
+
|
|
429
|
+
The templates favor:
|
|
430
|
+
|
|
431
|
+
1. literal XSD structure
|
|
432
|
+
2. active embedded Schematron
|
|
433
|
+
3. prose comments only when they do not conflict with 1 or 2
|
|
434
|
+
|
|
435
|
+
### Rationale
|
|
436
|
+
|
|
437
|
+
That order of trust is the safest way to avoid silently baking in rules that are described in comments but not actually present in the effective shipped schema binding.
|
|
438
|
+
|
|
439
|
+
---
|
|
440
|
+
|
|
441
|
+
## 7. What is still intentionally approximate
|
|
442
|
+
|
|
443
|
+
These templates are substantial, but they are still templates.
|
|
444
|
+
|
|
445
|
+
### 7.1 LOM leaf-level foreign attributes
|
|
446
|
+
|
|
447
|
+
The loose LOM profiles technically allow foreign attributes on many leaf nodes. The template does not attempt to preserve that with perfect fidelity everywhere.
|
|
448
|
+
|
|
449
|
+
### 7.2 Authorization workflow semantics
|
|
450
|
+
|
|
451
|
+
The authorization schema is now modeled structurally, but the templates still do **not** implement or validate any end-to-end authorization exchange or authenticated content access flow. They validate the schema shape only.
|
|
452
|
+
|
|
453
|
+
### 7.3 Full XML lexical fidelity
|
|
454
|
+
|
|
455
|
+
The templates are not a byte-level XML round-trip model.
|
|
456
|
+
|
|
457
|
+
For example:
|
|
458
|
+
|
|
459
|
+
- namespace prefixes are not preserved as first-class data
|
|
460
|
+
- attribute order is not preserved
|
|
461
|
+
- the exact XSD mechanism for unordered repeated `choice` groups is normalized away in LOM
|
|
462
|
+
|
|
463
|
+
### Rationale
|
|
464
|
+
|
|
465
|
+
All three omissions are deliberate. Modeling them exactly would make the templates much harder to use while adding comparatively little value for the likely TypeScript/Zod use case.
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## 8. How to interpret the output structure
|
|
470
|
+
|
|
471
|
+
The main source layout is:
|
|
472
|
+
|
|
473
|
+
- `packages/contracts/src/common-cartridge/v1_3/ccv1p3_imscp_v1p2_v1p0.ts`
|
|
474
|
+
- `packages/contracts/src/common-cartridge/v1_3/ccv1p3_imscsmd_v1p0.ts`
|
|
475
|
+
- `packages/contracts/src/common-cartridge/v1_3/ccv1p3_imsdt_v1p3.ts`
|
|
476
|
+
- `packages/contracts/src/common-cartridge/v1_3/ccv1p3_imswl_v1p3.ts`
|
|
477
|
+
- `packages/contracts/src/common-cartridge/v1_3/ccv1p3_lommanifest_v1p0.ts`
|
|
478
|
+
- `packages/contracts/src/common-cartridge/v1_3/ccv1p3_lomresource_v1p0.ts`
|
|
479
|
+
- `packages/contracts/src/common-cartridge/v1_3/ccv1p3_lomccltilink_v1p0.ts`
|
|
480
|
+
- `packages/contracts/src/common-cartridge/v1_3/ccv1p3_imsccauth_v1p3.ts`
|
|
481
|
+
- `packages/contracts/src/common-cartridge/v1_3/ccv1p3_qtiasiv1p2p1_v1p0.ts`
|
|
482
|
+
- `packages/contracts/src/common-cartridge/v1_3/index.ts`
|
|
483
|
+
|
|
484
|
+
The version barrel `packages/contracts/src/common-cartridge/v1_3/index.ts` re-exports the directory surface for this specific Common Cartridge version.
|
|
485
|
+
|
|
486
|
+
The most important exports are:
|
|
487
|
+
|
|
488
|
+
### Simpler direct mappings
|
|
489
|
+
|
|
490
|
+
- `CurriculumStandardsMetadataSetDocumentSchema`
|
|
491
|
+
- `DiscussionTopicDocumentSchema`
|
|
492
|
+
- `WebLinkDocumentSchema`
|
|
493
|
+
|
|
494
|
+
### LOM profiles
|
|
495
|
+
|
|
496
|
+
- `LomManifestDocumentSchema`
|
|
497
|
+
- `LomResourceDocumentSchema`
|
|
498
|
+
- `LomCcLtiLinkDocumentSchema`
|
|
499
|
+
|
|
500
|
+
### Common Cartridge manifest
|
|
501
|
+
|
|
502
|
+
- `CommonCartridgeAuthorizationsDocumentSchema`
|
|
503
|
+
- `CommonCartridgeManifestRawDocumentSchema`
|
|
504
|
+
- `CommonCartridgeManifestProfileDocumentSchema`
|
|
505
|
+
|
|
506
|
+
### Embedded QTI ASI profile
|
|
507
|
+
|
|
508
|
+
- `QtiQuestestinteropRawDocumentSchema`
|
|
509
|
+
- `QtiQuestestinteropProfileDocumentSchema`
|
|
510
|
+
|
|
511
|
+
### Convenience bundle
|
|
512
|
+
|
|
513
|
+
- `CommonCartridgeDerivedZodTemplates`
|
|
514
|
+
|
|
515
|
+
The raw/profile split is important:
|
|
516
|
+
|
|
517
|
+
- **raw** = XSD structure
|
|
518
|
+
- **profile** = XSD structure plus important Schematron-derived semantic checks
|
|
519
|
+
|
|
520
|
+
---
|
|
521
|
+
|
|
522
|
+
## 9. If this were taken further
|
|
523
|
+
|
|
524
|
+
The next logical refinements would be:
|
|
525
|
+
|
|
526
|
+
1. add parser adapters for a specific XML parser output shape
|
|
527
|
+
2. add parser-specific coercion or normalization for XML booleans/defaults such as `import` and `protected` if a concrete parser is chosen
|
|
528
|
+
3. add more complete LOM Schematron refinements if strict profile-level validation becomes a requirement
|
|
529
|
+
4. tighten the recursive schema typing so fewer helper-boundary casts are needed
|
|
530
|
+
|
|
531
|
+
The source is now split by schema file under `packages/contracts/src/common-cartridge/v1_3/`, with a version barrel preserved at `packages/contracts/src/common-cartridge/v1_3/index.ts`.
|