src/eric7/Plugins/CheckerPlugins/SyntaxChecker/jsCheckSyntax.py

branch
eric7
changeset 10341
3fdffd9cc21d
child 10439
21c28b0f9e41
equal deleted inserted replaced
10340:548b4c7f410e 10341:3fdffd9cc21d
1 # -*- coding: utf-8 -*-
2
3 # Copyright (c) 2014 - 2021 Detlev Offenbach <detlev@die-offenbachs.de>
4 # Copyright (c) 2023 Detlev Offenbach <detlev@die-offenbachs.de>
5 #
6
7 """
8 Module implementing the syntax check for JavaScript.
9 """
10
11 import multiprocessing
12 import queue
13
14
15 def initService():
16 """
17 Initialize the service and return the entry point.
18
19 @return the entry point for the background client
20 @rtype function
21 """
22 return jsSyntaxCheck
23
24
25 def initBatchService():
26 """
27 Initialize the batch service and return the entry point.
28
29 @return the entry point for the background client
30 @rtype function
31 """
32 return jsSyntaxBatchCheck
33
34
35 def jsSyntaxCheck(file, codestring):
36 """
37 Function to check a Javascript source file for syntax errors.
38
39 @param file source filename
40 @type str
41 @param codestring string containing the code to check
42 @type str
43 @return list of dictionaries with the key 'error' which contain a tuple with
44 details about the syntax error. Each tuple contains the file name, line
45 number, column, code string and the error message.
46 @rtype list of dict
47 """
48 return __jsSyntaxCheck(file, codestring)
49
50
51 def jsSyntaxBatchCheck(argumentsList, send, fx, cancelled, maxProcesses=0):
52 """
53 Module function to check syntax for a batch of files.
54
55 @param argumentsList list of arguments tuples as given for jsSyntaxCheck
56 @type list
57 @param send reference to send function
58 @type function
59 @param fx registered service name
60 @type str
61 @param cancelled reference to function checking for a cancellation
62 @type function
63 @param maxProcesses number of processes to be used
64 @type int
65 """
66 if maxProcesses == 0:
67 # determine based on CPU count
68 try:
69 NumberOfProcesses = multiprocessing.cpu_count()
70 if NumberOfProcesses >= 1:
71 NumberOfProcesses -= 1
72 except NotImplementedError:
73 NumberOfProcesses = 1
74 else:
75 NumberOfProcesses = maxProcesses
76
77 # Create queues
78 taskQueue = multiprocessing.Queue()
79 doneQueue = multiprocessing.Queue()
80
81 # Submit tasks (initially two time number of processes
82 tasks = len(argumentsList)
83 initialTasks = 2 * NumberOfProcesses
84 for _ in range(initialTasks):
85 taskQueue.put(argumentsList.pop(0))
86
87 # Start worker processes
88 workers = [
89 multiprocessing.Process(target=workerTask, args=(taskQueue, doneQueue))
90 for _ in range(NumberOfProcesses)
91 ]
92 for worker in workers:
93 worker.start()
94
95 # Get and send results
96 for _ in range(tasks):
97 resultSent = False
98 wasCancelled = False
99
100 while not resultSent:
101 try:
102 # get result (waiting max. 3 seconds and send it to frontend
103 filename, result = doneQueue.get()
104 send(fx, filename, result)
105 resultSent = True
106 except queue.Empty:
107 # ignore empty queue, just carry on
108 if cancelled():
109 wasCancelled = True
110 break
111
112 if wasCancelled or cancelled():
113 # just exit the loop ignoring the results of queued tasks
114 break
115
116 if argumentsList:
117 taskQueue.put(argumentsList.pop(0))
118
119 # Tell child processes to stop
120 for _ in range(NumberOfProcesses):
121 taskQueue.put("STOP")
122
123 for worker in workers:
124 worker.join()
125 worker.close()
126
127 taskQueue.close()
128 doneQueue.close()
129
130
131 def workerTask(inputQueue, outputQueue):
132 """
133 Module function acting as the parallel worker for the syntax check.
134
135 @param inputQueue input queue
136 @type multiprocessing.Queue
137 @param outputQueue output queue
138 @type multiprocessing.Queue
139 """
140 for filename, args in iter(inputQueue.get, "STOP"):
141 source = args[0]
142 result = __jsSyntaxCheck(filename, source)
143 outputQueue.put((filename, result))
144
145
146 def __jsSyntaxCheck(file, codestring):
147 """
148 Function to check a JavaScript source file for syntax errors.
149
150 @param file source filename
151 @type str
152 @param codestring string containing the code to check
153 @type str
154 @return list of dictionaries with the key 'error' which contain a tuple with
155 details about the syntax error. Each tuple contains the file name, line
156 number, column, code string and the error message.
157 @rtype list of dict
158 """
159 if codestring:
160 try:
161 import esprima # noqa: I101, I102
162 except ImportError:
163 error = "esprima not available. Install it via the PyPI interface."
164 return [{"error": (file, 0, 0, "", error)}]
165
166 try:
167 esprima.parse(codestring, esnext=True, sourceType="module")
168 # Parsing is just done to get syntax errors.
169 except esprima.Error as exc:
170 line = exc.lineNumber
171 column = exc.column
172 error = exc.message.split(":", 1)[-1].strip()
173
174 codelines = codestring.splitlines()
175 cline = min(len(codelines), line) - 1
176 code = codelines[cline]
177
178 return [{"error": (file, line, column, code, error)}]
179
180 return [{}]

eric ide

mercurial