11import * as JsonPointer from "@hyperjump/json-pointer" ;
22import { JsonLexer } from "./json-lexer.js" ;
3+ import { parse as parseYaml } from "yaml-unist-parser" ;
34
45/**
56 * @import { Node, Position } from "unist"
@@ -9,52 +10,59 @@ import { JsonLexer } from "./json-lexer.js";
910 * JsonNode,
1011 * JsonObjectNode,
1112 * JsonPropertyNameNode,
12- * JsonPropertyNode
13+ * JsonPropertyNode,
14+ * JsonStringNode
1315 * } from "./jsonast.d.ts"
16+ * @import {
17+ * YamlUnistNode,
18+ * MappingKey,
19+ * MappingItem,
20+ * FlowMappingItem,
21+ * ContentNode
22+ * } from "yaml-unist-parser"
1423 */
1524
16- /** @type (json: string, uri?: string ) => JsonNode */
17- export const fromJson = ( json , uri = "" ) => {
25+ /** @type (json: string) => JsonNode */
26+ export const fromJson = ( json ) => {
1827 const lexer = new JsonLexer ( json ) ;
1928
2029 const token = lexer . nextToken ( ) ;
21- const jsonValue = parseValue ( token , lexer , undefined , uri , "" ) ;
30+ const jsonValue = parseValue ( token , lexer , undefined ) ;
2231
2332 lexer . done ( ) ;
2433
2534 return jsonValue ;
2635} ;
2736
28- /** @type (token: JsonToken, lexer: JsonLexer, key: string | undefined, uri: string, pointer: string ) => JsonNode */
29- const parseValue = ( token , lexer , _key , uri , pointer ) => {
37+ /** @type (token: JsonToken, lexer: JsonLexer, key: string | undefined) => JsonNode */
38+ const parseValue = ( token , lexer , _key ) => {
3039 switch ( token . type ) {
3140 case "null" :
3241 case "boolean" :
3342 case "number" :
3443 case "string" :
35- return parseScalar ( token , uri , pointer ) ;
44+ return parseScalar ( token ) ;
3645 case "[" :
37- return parseArray ( token , lexer , uri , pointer ) ;
46+ return parseArray ( token , lexer ) ;
3847 case "{" :
39- return parseObject ( token , lexer , uri , pointer ) ;
48+ return parseObject ( token , lexer ) ;
4049 default :
4150 throw lexer . syntaxError ( "Expected a JSON value" , token ) ;
4251 }
4352} ;
4453
45- /** @type (token: JsonToken<"null" | "boolean" | "number" | "string">, uri: string, pointer: string ) => JsonNode */
46- const parseScalar = ( token , uri , pointer ) => {
54+ /** @type (token: JsonToken<"null" | "boolean" | "number" | "string">) => JsonNode */
55+ const parseScalar = ( token ) => {
4756 return {
4857 type : "json" ,
4958 jsonType : token . type ,
5059 value : JSON . parse ( token . value ) , // eslint-disable-line @typescript-eslint/no-unsafe-assignment
51- location : `${ uri } #${ encodeURI ( pointer ) } ` ,
5260 position : tokenPosition ( token )
5361 } ;
5462} ;
5563
56- /** @type (token: JsonToken, lexer: JsonLexer, key: string, uri: string, pointer: string ) => JsonPropertyNode */
57- const parseProperty = ( token , lexer , _key , uri , pointer ) => {
64+ /** @type (token: JsonToken, lexer: JsonLexer, key: string) => JsonPropertyNode */
65+ const parseProperty = ( token , lexer , _key ) => {
5866 if ( token . type !== "string" ) {
5967 throw lexer . syntaxError ( "Expected a propertry" , token ) ;
6068 }
@@ -71,7 +79,7 @@ const parseProperty = (token, lexer, _key, uri, pointer) => {
7179 throw lexer . syntaxError ( "Expected :" , token ) ;
7280 }
7381
74- const valueNode = parseValue ( lexer . nextToken ( ) , lexer , keyNode . value , uri , JsonPointer . append ( keyNode . value , pointer ) ) ;
82+ const valueNode = parseValue ( lexer . nextToken ( ) , lexer , keyNode . value ) ;
7583
7684 return {
7785 type : "json-property" ,
@@ -90,11 +98,11 @@ const parseProperty = (token, lexer, _key, uri, pointer) => {
9098
9199/**
92100 * @type <P extends ParentNode<C>, C extends JsonNode | JsonPropertyNode>(
93- * parseChild: (token: JsonToken, lexer: JsonLexer, key: string, uri: string, pointer: string ) => C,
101+ * parseChild: (token: JsonToken, lexer: JsonLexer, key: string) => C,
94102 * endToken: string
95- * ) => (lexer: JsonLexer, node: P, uri: string, pointer: string ) => P
103+ * ) => (lexer: JsonLexer, node: P) => P
96104 */
97- const parseCommaSeparated = ( parseChild , endToken ) => ( lexer , node , uri , pointer ) => {
105+ const parseCommaSeparated = ( parseChild , endToken ) => ( lexer , node ) => {
98106 for ( let index = 0 ; true ; index ++ ) {
99107 let token = lexer . nextToken ( ) ;
100108
@@ -111,44 +119,42 @@ const parseCommaSeparated = (parseChild, endToken) => (lexer, node, uri, pointer
111119 }
112120 }
113121
114- const childNode = parseChild ( token , lexer , `${ index } ` , uri , pointer ) ;
122+ const childNode = parseChild ( token , lexer , `${ index } ` ) ;
115123 if ( childNode ) {
116124 node . children . push ( childNode ) ;
117125 }
118126 }
119127} ;
120128
121- /** @type (openToken: JsonToken, lexer: JsonLexer, uri: string, pointer: string ) => JsonArrayNode */
122- const parseArray = ( openToken , lexer , uri , pointer ) => {
129+ /** @type (openToken: JsonToken, lexer: JsonLexer) => JsonArrayNode */
130+ const parseArray = ( openToken , lexer ) => {
123131 return parseItems ( lexer , {
124132 type : "json" ,
125133 jsonType : "array" ,
126134 children : [ ] ,
127- location : `${ uri } #${ encodeURI ( pointer ) } ` ,
128135 position : tokenPosition ( openToken )
129- } , uri , pointer ) ;
136+ } ) ;
130137} ;
131138
132- /** @type (token: JsonToken, lexer: JsonLexer, key: string, uri: string, pointer: string ) => JsonNode */
133- const parseItem = ( token , lexer , key , uri , pointer ) => {
134- return parseValue ( token , lexer , key , uri , JsonPointer . append ( key , pointer ) ) ;
139+ /** @type (token: JsonToken, lexer: JsonLexer, key: string) => JsonNode */
140+ const parseItem = ( token , lexer , key ) => {
141+ return parseValue ( token , lexer , key ) ;
135142} ;
136143
137- /** @type (lexer: JsonLexer, node: { type: "json" } & JsonArrayNode, uri: string, pointer: string ) => JsonArrayNode */
144+ /** @type (lexer: JsonLexer, node: { type: "json" } & JsonArrayNode) => JsonArrayNode */
138145const parseItems = parseCommaSeparated ( parseItem , "]" ) ;
139146
140- /** @type (openToken: JsonToken, lexer: JsonLexer, uri: string, pointer: string ) => JsonObjectNode */
141- const parseObject = ( openToken , lexer , uri , pointer ) => {
147+ /** @type (openToken: JsonToken, lexer: JsonLexer) => JsonObjectNode */
148+ const parseObject = ( openToken , lexer ) => {
142149 return parseProperties ( lexer , {
143150 type : "json" ,
144151 jsonType : "object" ,
145152 children : [ ] ,
146- location : `${ uri } #${ encodeURI ( pointer ) } ` ,
147153 position : tokenPosition ( openToken )
148- } , uri , pointer ) ;
154+ } ) ;
149155} ;
150156
151- /** @type (lexer: JsonLexer, node: { type: "json" } & JsonObjectNode, uri: string, pointer: string ) => JsonObjectNode */
157+ /** @type (lexer: JsonLexer, node: { type: "json" } & JsonObjectNode) => JsonObjectNode */
152158const parseProperties = parseCommaSeparated ( parseProperty , "}" ) ;
153159
154160/** @type (startToken: JsonToken, endToken?: JsonToken) => Position */
@@ -211,3 +217,121 @@ export const getNodeFromPointer = (tree, pointer, returnProperty) => {
211217
212218 return node . type === "json-property" && ! returnProperty ? node . children [ 1 ] : node ;
213219} ;
220+
221+ /** @type (yaml: string) => JsonNode */
222+ export const fromYaml = ( yaml ) => {
223+ const root = parseYaml ( yaml ) ;
224+ return yamlToJson ( root ) ;
225+ } ;
226+
227+ /**
228+ * @overload
229+ * @param {MappingItem | FlowMappingItem } yamlNode
230+ * @returns {JsonPropertyNode }
231+ *
232+ * @overload
233+ * @param {MappingKey } yamlNode
234+ * @returns {JsonPropertyNameNode }
235+ *
236+ * @overload
237+ * @param {ContentNode } yamlNode
238+ * @returns {JsonStringNode }
239+ *
240+ * @overload
241+ * @param {YamlUnistNode } yamlNode
242+ * @returns {JsonNode }
243+ *
244+ * @param {YamlUnistNode } yamlNode
245+ * @returns {JsonNode | JsonPropertyNode | JsonPropertyNameNode }
246+ */
247+ const yamlToJson = ( yamlNode ) => {
248+ switch ( yamlNode . type ) {
249+ case "root" :
250+ return yamlToJson ( yamlNode . children [ 0 ] ) ;
251+
252+ case "document" :
253+ return yamlToJson ( yamlNode . children [ 1 ] ) ;
254+
255+ case "documentHead" :
256+ throw Error ( `Not Implemented - ${ yamlNode . type } ` ) ;
257+
258+ case "documentBody" :
259+ if ( yamlNode . children . length === 0 ) {
260+ throw Error ( "YAML documents must contain a value" ) ;
261+ }
262+ return yamlToJson ( yamlNode . children [ 0 ] ) ;
263+
264+ case "plain" :
265+ case "quoteDouble" :
266+ case "quoteSingle" :
267+ case "blockLiteral" :
268+ case "blockFolded" :
269+ /** @type JsonStringNode */
270+ const stringNode = {
271+ type : "json" ,
272+ jsonType : "string" ,
273+ value : yamlNode . value ,
274+ position : yamlNode . position
275+ } ;
276+ return stringNode ;
277+
278+ case "mapping" :
279+ case "flowMapping" :
280+ /** @type JsonObjectNode */
281+ const objectNode = {
282+ type : "json" ,
283+ jsonType : "object" ,
284+ children : yamlNode . children . map ( ( mappingItemNode ) => yamlToJson ( mappingItemNode ) ) ,
285+ position : yamlNode . position
286+ } ;
287+ return objectNode ;
288+
289+ case "mappingItem" :
290+ case "flowMappingItem" :
291+ const [ mappingKeyNode , mappingValueNode ] = yamlNode . children ;
292+
293+ /** @type JsonPropertyNode */
294+ const propertyNode = {
295+ type : "json-property" ,
296+ children : [
297+ yamlToJson ( mappingKeyNode ) ,
298+ yamlToJson ( mappingValueNode )
299+ ] ,
300+ position : yamlNode . position
301+ } ;
302+
303+ return propertyNode ;
304+
305+ case "mappingKey" :
306+ const contentNode = yamlToJson ( /** @type ContentNode */ ( yamlNode . children [ 0 ] ) ) ;
307+ /** @type JsonPropertyNameNode */
308+ const propertyNameNode = {
309+ type : "json-property-name" ,
310+ jsonType : "string" ,
311+ value : contentNode . value ,
312+ position : yamlNode . position
313+ } ;
314+ return propertyNameNode ;
315+
316+ case "mappingValue" :
317+ return yamlToJson ( /** @type ContentNode */ ( yamlNode . children [ 0 ] ) ) ;
318+
319+ case "sequence" :
320+ case "flowSequence" :
321+ /** @type JsonArrayNode */
322+ const arrayNode = {
323+ type : "json" ,
324+ jsonType : "array" ,
325+ children : yamlNode . children . map ( ( sequenceItemNode ) => yamlToJson ( sequenceItemNode ) ) ,
326+ position : yamlNode . position
327+ } ;
328+ return arrayNode ;
329+
330+ case "sequenceItem" :
331+ case "flowSequenceItem" :
332+ return yamlToJson ( /** @type ContentNode */ ( yamlNode . children [ 0 ] ) ) ;
333+
334+ default :
335+ throw Error ( `YAML error. ${ yamlNode . type } ` ) ;
336+ }
337+ } ;
0 commit comments