@@ -188,7 +188,12 @@ public Object compact(Context activeCtx, String activeProperty, Object element,
188188 // 4
189189 if (elem .containsKey (JsonLdConsts .VALUE ) || elem .containsKey (JsonLdConsts .ID )) {
190190 final Object compactedValue = activeCtx .compactValue (activeProperty , elem );
191- if (!(compactedValue instanceof Map || compactedValue instanceof List )) {
191+ boolean isScalar = !(compactedValue instanceof Map || compactedValue instanceof List );
192+ // jsonld 1.1: 7 in https://w3c.github.io/json-ld-api/#algorithm-6
193+ boolean isJson = activeCtx .getTermDefinition (activeProperty ) != null
194+ && JsonLdConsts .JSON .equals (
195+ activeCtx .getTermDefinition (activeProperty ).get (JsonLdConsts .TYPE ));
196+ if (isScalar || isJson ) {
192197 return compactedValue ;
193198 }
194199 }
@@ -312,7 +317,9 @@ else if (JsonLdConsts.INDEX.equals(expandedProperty)
312317
313318 // NOTE: expanded value must be an array due to expansion
314319 // algorithm.
315-
320+ if (!(expandedValue instanceof List )) {
321+ throw new JsonLdError (Error .NOT_IMPLEMENTED , "no array: " + expandedValue );
322+ }
316323 // 7.5)
317324 if (((List <Object >) expandedValue ).size () == 0 ) {
318325 // 7.5.1)
@@ -514,6 +521,7 @@ public Object expand(Context activeCtx, String activeProperty, Object element)
514521 return null ;
515522 }
516523
524+ // GK: This would be the point to set `propertyScopedContext` to the `@context` entry for any term definition associated with `activeProperty`.
517525 // 3)
518526 if (element instanceof List ) {
519527 // 3.1)
@@ -546,14 +554,19 @@ else if (element instanceof Map) {
546554 // access helper
547555 final Map <String , Object > elem = (Map <String , Object >) element ;
548556 // 5)
557+ // This would be the place to revert the active context from any previous type-scoped context if the active context has a `previousContext` entry (with some exceptions when called from a map, or if it's a value object or a subject reference).
558+ // GK: If we found a `propertyScopedContext` above, we can parse it to create a new activeCtx using the `override protected` option
549559 if (elem .containsKey (JsonLdConsts .CONTEXT )) {
550560 activeCtx = activeCtx .parse (elem .get (JsonLdConsts .CONTEXT ));
551561 }
562+ // GK: This would be the place to remember this version of activeCtx as `typeScopedContext`.
552563 // 6)
553564 Map <String , Object > result = newMap ();
554565 // 7)
555566 final List <String > keys = new ArrayList <String >(elem .keySet ());
556567 Collections .sort (keys );
568+ // GK: This is the place to check for a type-scoped context by checking any key that expands to `@type` to see the current context has a term that equals that key where the term definition includes `@context`, updating the activeCtx as you go (but using termScopedContext when checking the keys).
569+ // GK: 1.1 made the following loop somewhat recursive, due to nesting, so might want to extract into a method.
557570 for (final String key : keys ) {
558571 final Object value = elem .get (key );
559572 // 7.1)
@@ -580,6 +593,8 @@ else if (element instanceof Map) {
580593 throw new JsonLdError (Error .COLLIDING_KEYWORDS ,
581594 expandedProperty + " already exists in result" );
582595 }
596+ // jsonld 1.1: 12 in https://w3c.github.io/json-ld-api/#algorithm-3
597+ Object inputType = elem .get (JsonLdConsts .TYPE );
583598 // 7.4.3)
584599 if (JsonLdConsts .ID .equals (expandedProperty )) {
585600 if (value instanceof String ) {
@@ -645,11 +660,23 @@ else if (JsonLdConsts.GRAPH.equals(expandedProperty)) {
645660 }
646661 // 7.4.6)
647662 else if (JsonLdConsts .VALUE .equals (expandedProperty )) {
648- if (value != null && (value instanceof Map || value instanceof List )) {
663+ // jsonld 1.1: 13.4.7.1 in https://w3c.github.io/json-ld-api/#algorithm-3
664+ if (JsonLdConsts .JSON .equals (inputType )) {
665+ expandedValue = value ;
666+ if (opts .getProcessingMode ().equals (JsonLdOptions .JSON_LD_1_0 )) {
667+ throw new JsonLdError (Error .INVALID_VALUE_OBJECT_VALUE , value );
668+ }
669+ }
670+ // jsonld 1.1: 13.4.7.2 in https://w3c.github.io/json-ld-api/#algorithm-3
671+ else if (value != null && (value instanceof Map || value instanceof List )) {
649672 throw new JsonLdError (Error .INVALID_VALUE_OBJECT_VALUE ,
650- "value of " + expandedProperty + " must be a scalar or null" );
673+ "value of " + expandedProperty + " must be a scalar or null, but was: " + value );
651674 }
652- expandedValue = value ;
675+ // jsonld 1.1: 13.4.7.3 in https://w3c.github.io/json-ld-api/#algorithm-3
676+ else {
677+ expandedValue = value ;
678+ }
679+ // jsonld 1.1: 13.4.7.4 in https://w3c.github.io/json-ld-api/#algorithm-3
653680 if (expandedValue == null ) {
654681 result .put (JsonLdConsts .VALUE , null );
655682 continue ;
@@ -766,6 +793,7 @@ else if (JsonLdConsts.REVERSE.equals(expandedProperty)) {
766793 }
767794 }
768795 }
796+ // GK: Also, `@included`, `@graph`, and `@direction`
769797 // 7.4.11.4)
770798 continue ;
771799 }
@@ -780,13 +808,26 @@ else if (frameExpansion && (JsonLdConsts.EXPLICIT.equals(expandedProperty)
780808 }
781809 // 7.4.12)
782810 if (expandedValue != null ) {
811+ /* jsonld 1.1: 13.4.16 in https://w3c.github.io/json-ld-api/#algorithm-3
812+ if (!(expandedValue == null && JsonLdConsts.VALUE.equals(expandedProperty)
813+ && (inputType == null || JsonLdConsts.JSON.equals(inputType)))) { */
783814 result .put (expandedProperty , expandedValue );
784815 }
785816 // 7.4.13)
786817 continue ;
787818 }
819+ // jsonld 1.1: 13.5 in https://w3c.github.io/json-ld-api/#algorithm-3
820+ String containerMapping = activeCtx .getContainer (key );
821+ // jsonld 1.1: 13.6 in https://w3c.github.io/json-ld-api/#algorithm-3
822+ if (activeCtx .getTermDefinition (key ) != null
823+ && JsonLdConsts .JSON .equals (activeCtx .getTermDefinition (key ).get (JsonLdConsts .TYPE ))) {
824+ Map <String , Object > newMap = newMap ();
825+ newMap .put (JsonLdConsts .VALUE , value );
826+ newMap .put (JsonLdConsts .TYPE , JsonLdConsts .JSON );
827+ expandedValue = newMap ;
828+ }
788829 // 7.5
789- else if (JsonLdConsts .LANGUAGE .equals (activeCtx . getContainer ( key ) )
830+ else if (JsonLdConsts .LANGUAGE .equals (containerMapping )
790831 && value instanceof Map ) {
791832 // 7.5.1)
792833 expandedValue = new ArrayList <Object >();
@@ -801,6 +842,10 @@ else if (JsonLdConsts.LANGUAGE.equals(activeCtx.getContainer(key))
801842 }
802843 // 7.5.2.2)
803844 for (final Object item : (List <Object >) languageValue ) {
845+ // jsonld 1.1: 13.7.4.2.1 in https://w3c.github.io/json-ld-api/#expansion-algorithm
846+ if (item == null ) {
847+ continue ;
848+ }
804849 // 7.5.2.2.1)
805850 if (!(item instanceof String )) {
806851 throw new JsonLdError (Error .INVALID_LANGUAGE_MAP_VALUE ,
@@ -815,9 +860,12 @@ else if (JsonLdConsts.LANGUAGE.equals(activeCtx.getContainer(key))
815860 }
816861 }
817862 // 7.6)
863+ // GK: Also a place to see if key is `@json` for JSON literals.
818864 else if (JsonLdConsts .INDEX .equals (activeCtx .getContainer (key ))
819865 && value instanceof Map ) {
820866 // 7.6.1)
867+ // GK: `@index` also supports property indexing, if the term definition includes `@index`.
868+ // GK: A map can also include `@none`.
821869 expandedValue = new ArrayList <Object >();
822870 // 7.6.2)
823871 final List <String > indexKeys = new ArrayList <String >(
@@ -865,6 +913,7 @@ else if (JsonLdConsts.INDEX.equals(activeCtx.getContainer(key))
865913 ((Map <String , Object >) expandedValue ).put (JsonLdConsts .LIST , tmp );
866914 }
867915 }
916+ // GK: Other container possibilities including `@graph`, `@id`, and `@type` along with variations.
868917 // 7.10)
869918 if (activeCtx .isReverseProperty (key )) {
870919 // 7.10.1)
@@ -937,8 +986,11 @@ else if (JsonLdConsts.INDEX.equals(activeCtx.getContainer(key))
937986 // null, so simply return it
938987 return null ;
939988 }
989+ else if (result .getOrDefault (JsonLdConsts .TYPE ,"" ).equals (JsonLdConsts .JSON )) {
990+ // jsonld 1.1: 14.3 in https://w3c.github.io/json-ld-api/#algorithm-3
991+ }
940992 // 8.3)
941- if (!(rval instanceof String ) && result .containsKey (JsonLdConsts .LANGUAGE )) {
993+ else if (!(rval instanceof String ) && result .containsKey (JsonLdConsts .LANGUAGE )) {
942994 throw new JsonLdError (Error .INVALID_LANGUAGE_TAGGED_VALUE ,
943995 "when @language is used, @value must be a string" );
944996 }
0 commit comments