1
+ const { workspace, window } = require ( 'vscode' )
2
+
3
+ let api = {
4
+ putDoc : ( ) => { } ,
5
+ compile : ( ) => { }
6
+ }
7
+
8
+ let log = msg => console . log ( 'cos.compile:' , msg )
9
+
10
+ // read from package.json, see below
11
+ let languages = [ 'cacheobjectscript' , 'cacheobjectscriptinclude' ] ;
12
+
13
+ const consoleOutput = ( output , defaultOutput = '' ) => {
14
+
15
+ const isArr = output instanceof Array
16
+ let out = isArr ? output . join ( '\n' )
17
+ : ( output || defaultOutput ) + ''
18
+ ;
19
+
20
+ out = out . replace ( / ^ [ \s \r \n ] + / , '' )
21
+
22
+ if ( out ) {
23
+ log ( out )
24
+ }
25
+
26
+ }
27
+
28
+
29
+ const checkEditor = ( ) => {
30
+
31
+ if ( ! window . activeTextEditor ) {
32
+ log ( 'No active editor, open one at first' )
33
+ return false
34
+ }
35
+
36
+ const openedDoc = window . activeTextEditor . document
37
+ if ( ! openedDoc ) {
38
+ log ( 'Open a Caché ObjectScript file first.' )
39
+ return false
40
+ }
41
+
42
+ const fullname = openedDoc . fileName
43
+ if ( ! fullname ) {
44
+ log ( 'You must save the document first' )
45
+ return false
46
+ }
47
+
48
+ const language = openedDoc . languageId
49
+ const supported = ~ languages . indexOf ( language )
50
+ if ( ! supported ) {
51
+ log (
52
+ `Document ${ fullname } cannot be compiled in Caché
53
+ ( type ${ language } unsupported )`
54
+ )
55
+ return false
56
+ }
57
+
58
+ return true
59
+
60
+ }
61
+
62
+
63
+ // is name correlate with code ?
64
+ // if ( atelier ) {
65
+ // testClass({ codename: 'test.class.cls', filename: 'class.cls' })
66
+ // } else {
67
+ // testClass({ codename: 'test.class.cls', filename: 'test.class.cls' })
68
+ //}
69
+ const testClass = ( { codename, filename } ) => {
70
+
71
+ const parts = codename . split ( / \. / g )
72
+ . filter ( s => ! ! s ) // for codename '.cls'
73
+
74
+ if ( parts . length < 3 ) { // 'cls' or empty
75
+ log (
76
+ `Unable to detect class name in source code of ${ filename } .\n
77
+ Is it a valid Caché ObjectScript class?`
78
+ )
79
+ return false
80
+ }
81
+
82
+ // NOTE: by default used package 'User'
83
+ // else if ( parts.length === 2 ){
84
+ // parts.unshift( 'User' ) //package by default
85
+ // or need detect 'import' directive
86
+ //}
87
+
88
+ const codenameL = codename . toLowerCase ( )
89
+ const filenameL = filename . toLowerCase ( )
90
+ const isContain = ~ codenameL . indexOf ( filenameL )
91
+
92
+ if ( ! isContain ) {
93
+
94
+ log (
95
+ `You tried to compile class named '${ docname } ' in file '${ filename } '.\n
96
+ Did you forget to rename the file/class to correspond to each other?`
97
+ )
98
+ return false
99
+
100
+ }
101
+ return true
102
+
103
+ }
104
+
105
+
106
+ const testRoutine = ( { codename, filename, type } ) => {
107
+
108
+ if ( ! codename ) {
109
+
110
+ log (
111
+
112
+ `Unable to detect routine name in source code of ${ filename } .
113
+ Is it a valid Caché ObjectScript routine? Did you forget to define a routine
114
+ name in the file on the first line? Routine code example:
115
+
116
+ ROUTINE RtnName [Type=MAC]
117
+ write "routine code here"
118
+ Quit
119
+ `
120
+ )
121
+ return false
122
+
123
+ }
124
+
125
+ const isContain = ~ codename . toLowerCase ( ) . indexOf ( filename . toLowerCase ( ) )
126
+ if ( ! isContain ) {
127
+ log (
128
+ `You tried to compile routine named "${ cacheDocName } " (.${ rtnType } ) in file "${
129
+ matchingFileName } ".\nDid you forget to rename the file/routine to correspond to each other? `
130
+ + `Routine code example: \n\n`
131
+ + `ROUTINE ${ matchingName } [Type=${ rtnType } ]`
132
+ + `\n write "routine code here"\n quit`
133
+ )
134
+ return false
135
+ }
136
+
137
+ return true
138
+
139
+
140
+ }
141
+
142
+ const AnyErrors = codename => ( err , res , keyword ) => {
143
+
144
+ if ( err ) {
145
+ const errtext = err . code ? err . code + ' ' + err . message : err
146
+ log ( `Unable to ${ keyword } ${ codename } : ${ errtext } ` )
147
+ return true
148
+ }
149
+
150
+
151
+ if ( ! res || ! res . status || ! ( res . status . errors instanceof Array ) ) {
152
+ log ( `Unknown response from Atelier API while trying to ${
153
+ keyword } ${ codename } : ${ res } ` )
154
+ return true
155
+ }
156
+
157
+ if ( res . result && res . result . status ) {
158
+ log ( res . result . status )
159
+ return true
160
+ }
161
+
162
+ if ( res . status . errors . length !== 0 ) {
163
+ log (
164
+ `Unable to ${ keyword } ${ codename } : ${ res . status . errors . summary }
165
+ ${ res . console } \n\n${ res . status . errors . join ( '\n' ) } `
166
+ )
167
+ return true
168
+ }
169
+
170
+ return false ;
171
+
172
+ }
173
+
174
+
175
+
176
+ /**
177
+ * Import and compile current file.
178
+ */
179
+ const cosCompile = ( ) => {
180
+
181
+ if ( ! checkEditor ( ) ) return
182
+
183
+ const activedoc = window . activeTextEditor . document
184
+ const fullname = activedoc . fileName
185
+ log ( `Saving ${ fullname } ...` )
186
+
187
+ //drop folders, all after last '/'
188
+ let filename = ( fullname . match ( / [ ^ \\ \/ ] + $ / ) || [ ] ) [ 0 ] || ''
189
+
190
+ let code = activedoc . getText ( )
191
+ . replace ( / \/ \/ [ ^ \r \n ] * \r ? \n / g, '' ) //normalize eol?
192
+
193
+ let codename ; //server side name
194
+
195
+ const isClass = / \. c l s $ / i. test ( fullname )
196
+ if ( isClass ) {
197
+
198
+ // Caché class files can be placed hierarchically (e.g. /src/Package/Class.cls),
199
+ // so we pick the class name from the class definition itself
200
+ const clsrgx = code . match ( / C l a s s ( [ ^ \s ] + ) / i ) // rgx = ['Class test.class', 'test.class']
201
+ codename = ( clsrgx || [ ] ) [ 1 ] || ''
202
+ codename += '.cls' // test.class.cls
203
+
204
+ // is name correlate with code ?
205
+ // if ( atelier_way ) {
206
+ // testClass({ codename: 'test.class.cls', filename: 'class.cls' })
207
+ // } else {
208
+ // testClass({ codename: 'test.class.cls', filename: 'test.class.cls' })
209
+ //}
210
+ if ( ! testClass ( { codename, filename } ) ) return
211
+
212
+ } else { // routine cases
213
+
214
+ // routine: routine name must be declared in a routine
215
+ const rtnrgx = code . match ( / r o u t i n e ( [ ^ \s ] + ) / i )
216
+ codename = ( rtnrgx || [ ] ) [ 1 ] || ''
217
+ const type = ( code . match ( / r o u t i n e \s + [ ^ \s ] + \s + \[ .* t y p e = ( [ a - z ] { 3 , } ) / i ) || [ ] ) [ 1 ] || 'MAC'
218
+ codename += '.' + type
219
+ if ( ! testRoutine ( { codename, filename, type } ) ) return
220
+
221
+ }
222
+
223
+ const content = code . split ( / \r ? \n / g ) // code lines
224
+ const anyErrors = AnyErrors ( codename )
225
+
226
+ const onCompile = ( err , res ) => {
227
+ if ( anyErrors ( err , res , 'compile' ) ) return
228
+ consoleOutput ( res . console || "Done." )
229
+ }
230
+
231
+ const onSave = ( err , res ) => {
232
+ if ( anyErrors ( err , res , 'save' ) ) return
233
+ consoleOutput ( res . console )
234
+ api . compile ( codename , onCompile )
235
+ }
236
+
237
+ api . putDoc (
238
+ codename ,
239
+ { enc : false , content } ,
240
+ { ignoreConflict : true } ,
241
+ onSave
242
+ )
243
+
244
+ }
245
+
246
+ module . exports = env => {
247
+
248
+ ( { log, api, languages } = env ) ;
249
+ return cosCompile
250
+
251
+ }
0 commit comments