11import either from '@matt.kantor/either'
2- import option from '@matt.kantor/option'
2+ import option , { type Option } from '@matt.kantor/option'
33import { parseArgs } from 'node:util'
44import { writeOutput } from '../cli/output.js'
55import { keywordHandlers as compilerKeywordHandlers } from '../compiling.js'
66import {
77 isFunctionNode ,
8+ keyPathToLookupExpression ,
89 makeFunctionNode ,
910 makeObjectNode ,
1011 readRuntimeExpression ,
1112 serialize ,
1213 types ,
1314 type KeywordHandlers ,
1415} from '../semantics.js'
16+ import type { NonEmptyKeyPath } from '../semantics/key-path.js'
1517import { prettyJson } from '../unparsing.js'
1618
17- const unserializableFunction = ( ) =>
18- either . makeLeft ( {
19- kind : 'unserializableValue' ,
20- message : 'this function cannot be serialized' ,
21- } )
19+ const serializeFunction =
20+ ( runtimeFunctionParameterName : Option < string > ) =>
21+ ( keyPath : NonEmptyKeyPath ) => {
22+ const serialize = either . map (
23+ option . match ( runtimeFunctionParameterName , {
24+ none : _ =>
25+ either . makeLeft ( {
26+ kind : 'unserializableValue' ,
27+ message : 'the runtime function cannot be serialized' ,
28+ } ) ,
29+ some : either . makeRight ,
30+ } ) ,
31+ parameterName => keyPathToLookupExpression ( [ parameterName , ...keyPath ] ) ,
32+ )
33+ return ( ) => serialize
34+ }
2235
23- const runtimeContext = makeObjectNode ( {
24- arguments : makeObjectNode ( {
25- lookup : makeFunctionNode (
26- {
27- parameter : types . atom ,
28- return : types . option ( types . atom ) ,
29- } ,
30- unserializableFunction ,
31- option . none ,
32- key => {
33- if ( typeof key !== 'string' ) {
34- return either . makeLeft ( {
35- kind : 'panic' ,
36- message : 'key was not an atom' ,
37- } )
38- } else {
39- const { values : argumentValues } = parseArgs ( {
40- args : process . argv ,
41- strict : false ,
42- options : {
43- [ key ] : { type : 'string' } ,
44- } ,
45- } )
46- const argument = argumentValues [ key ]
47- if ( typeof argument !== 'string' ) {
48- return either . makeRight (
49- makeObjectNode ( {
50- tag : 'none' ,
51- value : makeObjectNode ( { } ) ,
52- } ) ,
53- )
36+ const runtimeContext = ( runtimeFunctionParameterName : Option < string > ) => {
37+ const serializeRuntimeContextFunction = serializeFunction (
38+ runtimeFunctionParameterName ,
39+ )
40+ return makeObjectNode ( {
41+ arguments : makeObjectNode ( {
42+ lookup : makeFunctionNode (
43+ {
44+ parameter : types . atom ,
45+ return : types . option ( types . atom ) ,
46+ } ,
47+ serializeRuntimeContextFunction ( [ 'arguments' , 'lookup' ] ) ,
48+ option . none ,
49+ key => {
50+ if ( typeof key !== 'string' ) {
51+ return either . makeLeft ( {
52+ kind : 'panic' ,
53+ message : 'key was not an atom' ,
54+ } )
5455 } else {
55- return either . makeRight (
56- makeObjectNode ( {
57- tag : 'some' ,
58- value : argument ,
59- } ) ,
60- )
56+ const { values : argumentValues } = parseArgs ( {
57+ args : process . argv ,
58+ strict : false ,
59+ options : {
60+ [ key ] : { type : 'string' } ,
61+ } ,
62+ } )
63+ const argument = argumentValues [ key ]
64+ if ( typeof argument !== 'string' ) {
65+ return either . makeRight (
66+ makeObjectNode ( {
67+ tag : 'none' ,
68+ value : makeObjectNode ( { } ) ,
69+ } ) ,
70+ )
71+ } else {
72+ return either . makeRight (
73+ makeObjectNode ( {
74+ tag : 'some' ,
75+ value : argument ,
76+ } ) ,
77+ )
78+ }
6179 }
62- }
63- } ,
64- ) ,
65- } ) ,
66- environment : makeObjectNode ( {
67- lookup : makeFunctionNode (
80+ } ,
81+ ) ,
82+ } ) ,
83+ environment : makeObjectNode ( {
84+ lookup : makeFunctionNode (
85+ {
86+ parameter : types . atom ,
87+ return : types . option ( types . atom ) ,
88+ } ,
89+ serializeRuntimeContextFunction ( [ 'environment' , 'lookup' ] ) ,
90+ option . none ,
91+ key => {
92+ if ( typeof key !== 'string' ) {
93+ return either . makeLeft ( {
94+ kind : 'panic' ,
95+ message : 'key was not an atom' ,
96+ } )
97+ } else {
98+ const environmentVariable = process . env [ key ]
99+ if ( environmentVariable === undefined ) {
100+ return either . makeRight (
101+ makeObjectNode ( {
102+ tag : 'none' ,
103+ value : makeObjectNode ( { } ) ,
104+ } ) ,
105+ )
106+ } else {
107+ return either . makeRight (
108+ makeObjectNode ( {
109+ tag : 'some' ,
110+ value : environmentVariable ,
111+ } ) ,
112+ )
113+ }
114+ }
115+ } ,
116+ ) ,
117+ } ) ,
118+ log : makeFunctionNode (
68119 {
69- parameter : types . atom ,
70- return : types . option ( types . atom ) ,
120+ parameter : types . something ,
121+ return : types . object ,
71122 } ,
72- unserializableFunction ,
123+ serializeRuntimeContextFunction ( [ 'log' ] ) ,
73124 option . none ,
74- key => {
75- if ( typeof key !== 'string' ) {
125+ output => {
126+ const serializationResult = serialize ( output )
127+ if ( either . isLeft ( serializationResult ) ) {
76128 return either . makeLeft ( {
77129 kind : 'panic' ,
78- message : 'key was not an atom' ,
130+ message : serializationResult . value . message ,
79131 } )
80132 } else {
81- const environmentVariable = process . env [ key ]
82- if ( environmentVariable === undefined ) {
83- return either . makeRight (
84- makeObjectNode ( {
85- tag : 'none' ,
86- value : makeObjectNode ( { } ) ,
87- } ) ,
88- )
89- } else {
90- return either . makeRight (
91- makeObjectNode ( {
92- tag : 'some' ,
93- value : environmentVariable ,
94- } ) ,
95- )
96- }
133+ writeOutput ( process . stderr , prettyJson , serializationResult . value )
134+ return either . makeRight ( output )
97135 }
98136 } ,
99137 ) ,
100- } ) ,
101- log : makeFunctionNode (
102- {
103- parameter : types . something ,
104- return : types . object ,
105- } ,
106- unserializableFunction ,
107- option . none ,
108- output => {
109- const serializationResult = serialize ( output )
110- if ( either . isLeft ( serializationResult ) ) {
111- return either . makeLeft ( {
112- kind : 'panic' ,
113- message : serializationResult . value . message ,
114- } )
115- } else {
116- writeOutput ( process . stderr , prettyJson , serializationResult . value )
117- return either . makeRight ( output )
118- }
119- } ,
120- ) ,
121- program : makeObjectNode ( {
122- start_time : new Date ( ) . toISOString ( ) ,
123- } ) ,
124- } )
138+ program : makeObjectNode ( {
139+ start_time : new Date ( ) . toISOString ( ) ,
140+ } ) ,
141+ } )
142+ }
125143
126144export const keywordHandlers : KeywordHandlers = {
127145 ...compilerKeywordHandlers ,
@@ -139,7 +157,9 @@ export const keywordHandlers: KeywordHandlers = {
139157 'a function must be provided via the property `function` or `0`' ,
140158 } )
141159 } else {
142- const result = runtimeFunction ( runtimeContext )
160+ const result = runtimeFunction (
161+ runtimeContext ( runtimeFunction . parameterName ) ,
162+ )
143163 if ( either . isLeft ( result ) ) {
144164 // The runtime function panicked or had an unavailable dependency (which results in a panic
145165 // anyway in this context).
0 commit comments