Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions cli.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@

(define-enum-type resyntax-output-format (plain-text github-pull-request-review git-commit-message json))
(define-enum-type resyntax-fix-method (modify-files create-multiple-git-commits))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination analyzer-timeout-ms))


(define-record-type resyntax-fix-options
Expand All@@ -48,7 +48,8 @@
max-fixes
max-modified-files
max-modified-lines
max-pass-count))
max-pass-count
analyzer-timeout-ms))


(define all-lines (range-set (unbounded-range #:comparator natural<=>)))
Expand All@@ -60,6 +61,7 @@
(define selected-rule #false)
(define output-format plain-text)
(define output-destination 'console)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax analyze"
Expand DownExpand Up@@ -105,6 +107,11 @@ changed relative to baseref are analyzed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--output-to-file"
outputpath
"Store results in a file instead of printing them to the console."
Expand All@@ -128,7 +135,8 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
#:targets (build-vector targets)
#:suite suite
#:output-format output-format
#:output-destination output-destination))
#:output-destination output-destination
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-fix-parse-command-line)
Expand All@@ -143,6 +151,7 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
(define max-pass-count 10)
(define max-modified-files +inf.0)
(define max-modified-lines +inf.0)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax fix"
Expand DownExpand Up@@ -197,6 +206,11 @@ changed relative to baseref are analyzed and fixed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--max-pass-count"
passcount
"The maximum number of times Resyntax will fix each file. By default, Resyntax runs at most 10 \
Expand DownExpand Up@@ -235,7 +249,8 @@ are needed when applying a fix unlocks further fixes."
#:max-fixes max-fixes
#:max-modified-files max-modified-files
#:max-modified-lines max-modified-lines
#:max-pass-count max-pass-count))
#:max-pass-count max-pass-count
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-run)
Expand DownExpand Up@@ -273,7 +288,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
(define analysis
(resyntax-analyze-all sources
#:suite (resyntax-analyze-options-suite options)
#:max-passes 1))
#:max-passes 1
#:timeout-ms (resyntax-analyze-options-analyzer-timeout-ms options)))
(define results
(transduce (resyntax-analysis-all-results analysis)
(append-mapping in-hash-values)
Expand DownExpand Up@@ -322,7 +338,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
#:max-fixes (resyntax-fix-options-max-fixes options)
#:max-passes (resyntax-fix-options-max-pass-count options)
#:max-modified-sources max-modified-files
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms (resyntax-fix-options-analyzer-timeout-ms options)))
(match fix-method
[(== modify-files)
(resyntax-analysis-write-file-changes! analysis)]
Expand Down
34 changes: 22 additions & 12 deletions main.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,17 +17,18 @@
[resyntax-analysis-write-file-changes! (-> resyntax-analysis? void?)]
[resyntax-analysis-commit-fixes! (-> resyntax-analysis? void?)]
[resyntax-analyze
(->* (source?) (#:suite refactoring-suite? #:lines range-set?) refactoring-result-set?)]
(->* (source?) (#:suite refactoring-suite? #:lines range-set? #:timeout-ms exact-nonnegative-integer?) refactoring-result-set?)]
[resyntax-analyze-all
(->* ((hash/c source? range-set? #:flat? #true))
(#:suite refactoring-suite?
#:max-fixes (or/c exact-nonnegative-integer? +inf.0)
#:max-passes exact-nonnegative-integer?
#:max-modified-sources (or/c exact-nonnegative-integer? +inf.0)
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0))
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0)
#:timeout-ms exact-nonnegative-integer?)
resyntax-analysis?)]
[reysntax-analyze-for-properties-only
(->* (source?) (#:suite refactoring-suite?) syntax-property-bundle?)]
(->* (source?) (#:suite refactoring-suite? #:timeout-ms exact-nonnegative-integer?) syntax-property-bundle?)]
[refactor! (-> (sequence/c refactoring-result?) void?)]))


Expand DownExpand Up@@ -167,7 +168,8 @@

(define/guard (resyntax-analyze source
#:suite [suite default-recommendations]
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define source-lang (source-read-language source))
(guard source-lang #:else
Expand DownExpand Up@@ -210,7 +212,8 @@
(with-handlers ([exn:fail? skip])
(define analysis (source-analyze source
#:lines lines
#:analyzers (refactoring-suite-analyzers effective-suite)))
#:analyzers (refactoring-suite-analyzers effective-suite)
#:timeout-ms timeout-ms))
(refactor-visited-forms
#:analysis analysis #:suite effective-suite #:comments comments #:lines lines)))

Expand All@@ -229,7 +232,9 @@
[else result-set]))


(define/guard (reysntax-analyze-for-properties-only source #:suite [suite default-recommendations])
(define/guard (reysntax-analyze-for-properties-only source
#:suite [suite default-recommendations]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define full-source (source->string source))
(guard (string-prefix? full-source "#lang racket") #:else
Expand All@@ -251,7 +256,8 @@
[exn:fail:filesystem:missing-module? skip]
[exn:fail:contract:variable? skip])
(define analysis (source-analyze source
#:analyzers (refactoring-suite-analyzers suite)))
#:analyzers (refactoring-suite-analyzers suite)
#:timeout-ms timeout-ms))
(source-code-analysis-added-syntax-properties analysis)))


Expand All@@ -260,7 +266,8 @@
#:max-fixes [max-fixes +inf.0]
#:max-passes [max-passes 10]
#:max-modified-sources [max-modified-sources +inf.0]
#:max-modified-lines [max-modified-lines +inf.0])
#:max-modified-lines [max-modified-lines +inf.0]
#:timeout-ms [timeout-ms 10000])
(log-resyntax-info "--- analyzing code ---")
(for/fold ([pass-result-lists '()]
[sources sources]
Expand All@@ -274,7 +281,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms))
(define pass-fix-count (count-total-results pass-results))
(define new-max-fixes (- max-fixes pass-fix-count))]
#:break (hash-empty? pass-results)
Expand All@@ -298,7 +306,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines)
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms)
(transduce (in-hash-entries sources) ; entries with source keys and line range set values

;; The following steps perform a kind of layered shuffle: the files to refactor are
Expand DownExpand Up@@ -326,7 +335,7 @@
(append-mapping
(λ (e)
(match-define (entry source lines) e)
(define result-set (resyntax-analyze source #:suite suite #:lines lines))
(define result-set (resyntax-analyze source #:suite suite #:lines lines #:timeout-ms timeout-ms))
(refactoring-result-set-results result-set)))
(limiting max-modified-lines
#:by (λ (result)
Expand DownExpand Up@@ -524,6 +533,7 @@
;; Test with multipass analyze
(define analysis
(resyntax-analyze-all (hash test-source (range-set (unbounded-range #:comparator natural<=>)))
#:suite breaking-suite))
#:suite breaking-suite
#:timeout-ms 10000))
(check-equal? (resyntax-analysis-total-fixes analysis) 0
"Breaking suggestions should be filtered from resyntax-analyze-all")))
43 changes: 19 additions & 24 deletions private/analysis.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@

(provide
(contract-out
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?))
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?) #:timeout-ms exact-nonnegative-integer?)
(#:lines range-set?)
source-code-analysis?)]
[source-code-analysis? (-> any/c boolean?)]
Expand DownExpand Up@@ -68,15 +68,9 @@
(syntax-ref stx path)))


;; Timeout for analyzers in seconds
(define analyzer-timeout-seconds 10)

;; Milliseconds per second (for time conversions)
(define milliseconds-per-second 1000)

;; Run an analyzer with a timeout. Returns the result or an empty syntax property bundle
;; if timeout occurred or an error was raised.
(define (run-analyzer-with-timeout analyzer expanded source-name)
(define (run-analyzer-with-timeout analyzer expanded source-name timeout-ms)
(define result-box (box #false))
(define error-box (box #false))
(define start-time (current-inexact-milliseconds))
Expand All@@ -87,8 +81,7 @@
(with-handlers ([exn:fail? (λ (e) (set-box! error-box e))])
(set-box! result-box (expansion-analyze analyzer expanded))))))

(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds)
(* analyzer-timeout-seconds milliseconds-per-second))))
(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds) timeout-ms)))

;; Wait for either completion or timeout
(define final-result
Expand All@@ -100,9 +93,9 @@
[(eq? final-result 'timeout)
(kill-thread analyzer-thread)
(log-resyntax-warning
"analyzer ~a timed out after ~a seconds while analyzing ~a"
"analyzer ~a timed out after ~a ms while analyzing ~a"
(object-name analyzer)
analyzer-timeout-seconds
timeout-ms
source-name)
(syntax-property-bundle)]
[else
Expand All@@ -125,7 +118,8 @@

(define (source-analyze code
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:analyzers analyzers)
#:analyzers analyzers
#:timeout-ms timeout-ms)
(define ns (make-base-namespace))
(parameterize ([current-directory (or (source-directory code) (current-directory))]
[current-namespace ns])
Expand DownExpand Up@@ -245,7 +239,7 @@
(transduce analyzers
(append-mapping
(λ (analyzer)
(define result (run-analyzer-with-timeout analyzer expanded program-source-name))
(define result (run-analyzer-with-timeout analyzer expanded program-source-name timeout-ms))
(syntax-property-bundle-entries result)))
(filtering
(λ (prop-entry)
Expand DownExpand Up@@ -312,20 +306,21 @@
(define test-source (string-source "#lang racket/base (define x 1)"))

;; Test with empty analyzers list
(define analysis-empty (source-analyze test-source #:analyzers '()))
(define analysis-empty (source-analyze test-source #:analyzers '() #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-empty))

;; Test with single analyzer
(define analysis-single
(source-analyze test-source #:analyzers (list identifier-usage-analyzer)))
(source-analyze test-source #:analyzers (list identifier-usage-analyzer) #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-single))

;; Test with default analyzers (should match default behavior)
(define analysis-default
(source-analyze test-source
#:analyzers (list identifier-usage-analyzer
ignored-result-values-analyzer
variable-mutability-analyzer)))
variable-mutability-analyzer)
#:timeout-ms 10000))
(check-true (source-code-analysis? analysis-default)))

(test-case "source-analyze filters out properties with invalid paths"
Expand All@@ -345,7 +340,7 @@
(syntax-property-entry (syntax-path (list 0 999)) 'another-invalid-prop #true)))))

;; Run analysis with the bad analyzer - should not crash
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed successfully
(check-true (source-code-analysis? analysis))
Expand All@@ -372,13 +367,13 @@
(make-expansion-analyzer
#:name 'slow-analyzer
(λ (expanded)
;; Sleep for 11 seconds - slightly longer than the 10 second timeout
(sleep 11)
;; Sleep for 200ms - longer than a 100ms timeout
(sleep 0.2)
(syntax-property-bundle
(syntax-property-entry empty-syntax-path 'slow-prop #true)))))

;; Run analysis with the slow analyzer - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer)))
;; Run analysis with the slow analyzer and a short timeout - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer) #:timeout-ms 100))

;; Check that the analysis completed (even though the analyzer timed out)
(check-true (source-code-analysis? analysis))
Expand All@@ -403,7 +398,7 @@
(syntax-property-entry empty-syntax-path 'fast-prop #true)))))

;; Run analysis with the fast analyzer - should complete successfully
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed
(check-true (source-code-analysis? analysis))
Expand All@@ -427,7 +422,7 @@
(error "intentional test error"))))

;; Run analysis with the failing analyzer - should skip it and not crash
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed (even though the analyzer failed)
(check-true (source-code-analysis? analysis))))
16 changes: 15 additions & 1 deletion test.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,7 +147,21 @@

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-line-mask)
#:with (value ...) (list #'line-set)))
#:with (value ...) (list #'line-set))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-analyzer-timeout-millis)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...)))
(#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-line-mask #'current-analyzer-timeout-millis)
#:with (value ...) (list #'line-set #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number)
(#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-analyzer-timeout-millis #'current-line-mask)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value) #'line-set)))

(define-splicing-syntax-class code-block-test-args
#:attributes ([check 1])
Expand Down
18 changes: 18 additions & 0 deletions test/analyzer-timeout-test.rkt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
#lang resyntax/test


header:
------------------------------
#lang racket/base
------------------------------


test: "timeout parameter can be customized in tests"
@analyzer-timeout-millis 5000
- (or 1 (or 2 3))
- (or 1 2 3)


no-change-test: "timeout parameter works with no-change-test"
@analyzer-timeout-millis 5000
- (define x 42)
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions cli.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@

(define-enum-type resyntax-output-format (plain-text github-pull-request-review git-commit-message json))
(define-enum-type resyntax-fix-method (modify-files create-multiple-git-commits))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination analyzer-timeout-ms))


(define-record-type resyntax-fix-options
Expand All@@ -48,7 +48,8 @@
max-fixes
max-modified-files
max-modified-lines
max-pass-count))
max-pass-count
analyzer-timeout-ms))


(define all-lines (range-set (unbounded-range #:comparator natural<=>)))
Expand All@@ -60,6 +61,7 @@
(define selected-rule #false)
(define output-format plain-text)
(define output-destination 'console)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax analyze"
Expand DownExpand Up@@ -105,6 +107,11 @@ changed relative to baseref are analyzed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--output-to-file"
outputpath
"Store results in a file instead of printing them to the console."
Expand All@@ -128,7 +135,8 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
#:targets (build-vector targets)
#:suite suite
#:output-format output-format
#:output-destination output-destination))
#:output-destination output-destination
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-fix-parse-command-line)
Expand All@@ -143,6 +151,7 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
(define max-pass-count 10)
(define max-modified-files +inf.0)
(define max-modified-lines +inf.0)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax fix"
Expand DownExpand Up@@ -197,6 +206,11 @@ changed relative to baseref are analyzed and fixed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--max-pass-count"
passcount
"The maximum number of times Resyntax will fix each file. By default, Resyntax runs at most 10 \
Expand DownExpand Up@@ -235,7 +249,8 @@ are needed when applying a fix unlocks further fixes."
#:max-fixes max-fixes
#:max-modified-files max-modified-files
#:max-modified-lines max-modified-lines
#:max-pass-count max-pass-count))
#:max-pass-count max-pass-count
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-run)
Expand DownExpand Up@@ -273,7 +288,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
(define analysis
(resyntax-analyze-all sources
#:suite (resyntax-analyze-options-suite options)
#:max-passes 1))
#:max-passes 1
#:timeout-ms (resyntax-analyze-options-analyzer-timeout-ms options)))
(define results
(transduce (resyntax-analysis-all-results analysis)
(append-mapping in-hash-values)
Expand DownExpand Up@@ -322,7 +338,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
#:max-fixes (resyntax-fix-options-max-fixes options)
#:max-passes (resyntax-fix-options-max-pass-count options)
#:max-modified-sources max-modified-files
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms (resyntax-fix-options-analyzer-timeout-ms options)))
(match fix-method
[(== modify-files)
(resyntax-analysis-write-file-changes! analysis)]
Expand Down
34 changes: 22 additions & 12 deletions main.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,17 +17,18 @@
[resyntax-analysis-write-file-changes! (-> resyntax-analysis? void?)]
[resyntax-analysis-commit-fixes! (-> resyntax-analysis? void?)]
[resyntax-analyze
(->* (source?) (#:suite refactoring-suite? #:lines range-set?) refactoring-result-set?)]
(->* (source?) (#:suite refactoring-suite? #:lines range-set? #:timeout-ms exact-nonnegative-integer?) refactoring-result-set?)]
[resyntax-analyze-all
(->* ((hash/c source? range-set? #:flat? #true))
(#:suite refactoring-suite?
#:max-fixes (or/c exact-nonnegative-integer? +inf.0)
#:max-passes exact-nonnegative-integer?
#:max-modified-sources (or/c exact-nonnegative-integer? +inf.0)
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0))
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0)
#:timeout-ms exact-nonnegative-integer?)
resyntax-analysis?)]
[reysntax-analyze-for-properties-only
(->* (source?) (#:suite refactoring-suite?) syntax-property-bundle?)]
(->* (source?) (#:suite refactoring-suite? #:timeout-ms exact-nonnegative-integer?) syntax-property-bundle?)]
[refactor! (-> (sequence/c refactoring-result?) void?)]))


Expand DownExpand Up@@ -167,7 +168,8 @@

(define/guard (resyntax-analyze source
#:suite [suite default-recommendations]
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define source-lang (source-read-language source))
(guard source-lang #:else
Expand DownExpand Up@@ -210,7 +212,8 @@
(with-handlers ([exn:fail? skip])
(define analysis (source-analyze source
#:lines lines
#:analyzers (refactoring-suite-analyzers effective-suite)))
#:analyzers (refactoring-suite-analyzers effective-suite)
#:timeout-ms timeout-ms))
(refactor-visited-forms
#:analysis analysis #:suite effective-suite #:comments comments #:lines lines)))

Expand All@@ -229,7 +232,9 @@
[else result-set]))


(define/guard (reysntax-analyze-for-properties-only source #:suite [suite default-recommendations])
(define/guard (reysntax-analyze-for-properties-only source
#:suite [suite default-recommendations]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define full-source (source->string source))
(guard (string-prefix? full-source "#lang racket") #:else
Expand All@@ -251,7 +256,8 @@
[exn:fail:filesystem:missing-module? skip]
[exn:fail:contract:variable? skip])
(define analysis (source-analyze source
#:analyzers (refactoring-suite-analyzers suite)))
#:analyzers (refactoring-suite-analyzers suite)
#:timeout-ms timeout-ms))
(source-code-analysis-added-syntax-properties analysis)))


Expand All@@ -260,7 +266,8 @@
#:max-fixes [max-fixes +inf.0]
#:max-passes [max-passes 10]
#:max-modified-sources [max-modified-sources +inf.0]
#:max-modified-lines [max-modified-lines +inf.0])
#:max-modified-lines [max-modified-lines +inf.0]
#:timeout-ms [timeout-ms 10000])
(log-resyntax-info "--- analyzing code ---")
(for/fold ([pass-result-lists '()]
[sources sources]
Expand All@@ -274,7 +281,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms))
(define pass-fix-count (count-total-results pass-results))
(define new-max-fixes (- max-fixes pass-fix-count))]
#:break (hash-empty? pass-results)
Expand All@@ -298,7 +306,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines)
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms)
(transduce (in-hash-entries sources) ; entries with source keys and line range set values

;; The following steps perform a kind of layered shuffle: the files to refactor are
Expand DownExpand Up@@ -326,7 +335,7 @@
(append-mapping
(λ (e)
(match-define (entry source lines) e)
(define result-set (resyntax-analyze source #:suite suite #:lines lines))
(define result-set (resyntax-analyze source #:suite suite #:lines lines #:timeout-ms timeout-ms))
(refactoring-result-set-results result-set)))
(limiting max-modified-lines
#:by (λ (result)
Expand DownExpand Up@@ -524,6 +533,7 @@
;; Test with multipass analyze
(define analysis
(resyntax-analyze-all (hash test-source (range-set (unbounded-range #:comparator natural<=>)))
#:suite breaking-suite))
#:suite breaking-suite
#:timeout-ms 10000))
(check-equal? (resyntax-analysis-total-fixes analysis) 0
"Breaking suggestions should be filtered from resyntax-analyze-all")))
43 changes: 19 additions & 24 deletions private/analysis.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@

(provide
(contract-out
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?))
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?) #:timeout-ms exact-nonnegative-integer?)
(#:lines range-set?)
source-code-analysis?)]
[source-code-analysis? (-> any/c boolean?)]
Expand DownExpand Up@@ -68,15 +68,9 @@
(syntax-ref stx path)))


;; Timeout for analyzers in seconds
(define analyzer-timeout-seconds 10)

;; Milliseconds per second (for time conversions)
(define milliseconds-per-second 1000)

;; Run an analyzer with a timeout. Returns the result or an empty syntax property bundle
;; if timeout occurred or an error was raised.
(define (run-analyzer-with-timeout analyzer expanded source-name)
(define (run-analyzer-with-timeout analyzer expanded source-name timeout-ms)
(define result-box (box #false))
(define error-box (box #false))
(define start-time (current-inexact-milliseconds))
Expand All@@ -87,8 +81,7 @@
(with-handlers ([exn:fail? (λ (e) (set-box! error-box e))])
(set-box! result-box (expansion-analyze analyzer expanded))))))

(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds)
(* analyzer-timeout-seconds milliseconds-per-second))))
(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds) timeout-ms)))

;; Wait for either completion or timeout
(define final-result
Expand All@@ -100,9 +93,9 @@
[(eq? final-result 'timeout)
(kill-thread analyzer-thread)
(log-resyntax-warning
"analyzer ~a timed out after ~a seconds while analyzing ~a"
"analyzer ~a timed out after ~a ms while analyzing ~a"
(object-name analyzer)
analyzer-timeout-seconds
timeout-ms
source-name)
(syntax-property-bundle)]
[else
Expand All@@ -125,7 +118,8 @@

(define (source-analyze code
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:analyzers analyzers)
#:analyzers analyzers
#:timeout-ms timeout-ms)
(define ns (make-base-namespace))
(parameterize ([current-directory (or (source-directory code) (current-directory))]
[current-namespace ns])
Expand DownExpand Up@@ -245,7 +239,7 @@
(transduce analyzers
(append-mapping
(λ (analyzer)
(define result (run-analyzer-with-timeout analyzer expanded program-source-name))
(define result (run-analyzer-with-timeout analyzer expanded program-source-name timeout-ms))
(syntax-property-bundle-entries result)))
(filtering
(λ (prop-entry)
Expand DownExpand Up@@ -312,20 +306,21 @@
(define test-source (string-source "#lang racket/base (define x 1)"))

;; Test with empty analyzers list
(define analysis-empty (source-analyze test-source #:analyzers '()))
(define analysis-empty (source-analyze test-source #:analyzers '() #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-empty))

;; Test with single analyzer
(define analysis-single
(source-analyze test-source #:analyzers (list identifier-usage-analyzer)))
(source-analyze test-source #:analyzers (list identifier-usage-analyzer) #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-single))

;; Test with default analyzers (should match default behavior)
(define analysis-default
(source-analyze test-source
#:analyzers (list identifier-usage-analyzer
ignored-result-values-analyzer
variable-mutability-analyzer)))
variable-mutability-analyzer)
#:timeout-ms 10000))
(check-true (source-code-analysis? analysis-default)))

(test-case "source-analyze filters out properties with invalid paths"
Expand All@@ -345,7 +340,7 @@
(syntax-property-entry (syntax-path (list 0 999)) 'another-invalid-prop #true)))))

;; Run analysis with the bad analyzer - should not crash
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed successfully
(check-true (source-code-analysis? analysis))
Expand All@@ -372,13 +367,13 @@
(make-expansion-analyzer
#:name 'slow-analyzer
(λ (expanded)
;; Sleep for 11 seconds - slightly longer than the 10 second timeout
(sleep 11)
;; Sleep for 200ms - longer than a 100ms timeout
(sleep 0.2)
(syntax-property-bundle
(syntax-property-entry empty-syntax-path 'slow-prop #true)))))

;; Run analysis with the slow analyzer - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer)))
;; Run analysis with the slow analyzer and a short timeout - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer) #:timeout-ms 100))

;; Check that the analysis completed (even though the analyzer timed out)
(check-true (source-code-analysis? analysis))
Expand All@@ -403,7 +398,7 @@
(syntax-property-entry empty-syntax-path 'fast-prop #true)))))

;; Run analysis with the fast analyzer - should complete successfully
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed
(check-true (source-code-analysis? analysis))
Expand All@@ -427,7 +422,7 @@
(error "intentional test error"))))

;; Run analysis with the failing analyzer - should skip it and not crash
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed (even though the analyzer failed)
(check-true (source-code-analysis? analysis))))
16 changes: 15 additions & 1 deletion test.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,7 +147,21 @@

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-line-mask)
#:with (value ...) (list #'line-set)))
#:with (value ...) (list #'line-set))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-analyzer-timeout-millis)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...)))
(#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-line-mask #'current-analyzer-timeout-millis)
#:with (value ...) (list #'line-set #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number)
(#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-analyzer-timeout-millis #'current-line-mask)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value) #'line-set)))

(define-splicing-syntax-class code-block-test-args
#:attributes ([check 1])
Expand Down
18 changes: 18 additions & 0 deletions test/analyzer-timeout-test.rkt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
#lang resyntax/test


header:
------------------------------
#lang racket/base
------------------------------


test: "timeout parameter can be customized in tests"
@analyzer-timeout-millis 5000
- (or 1 (or 2 3))
- (or 1 2 3)


no-change-test: "timeout parameter works with no-change-test"
@analyzer-timeout-millis 5000
- (define x 42)
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions cli.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@

(define-enum-type resyntax-output-format (plain-text github-pull-request-review git-commit-message json))
(define-enum-type resyntax-fix-method (modify-files create-multiple-git-commits))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination analyzer-timeout-ms))


(define-record-type resyntax-fix-options
Expand All@@ -48,7 +48,8 @@
max-fixes
max-modified-files
max-modified-lines
max-pass-count))
max-pass-count
analyzer-timeout-ms))


(define all-lines (range-set (unbounded-range #:comparator natural<=>)))
Expand All@@ -60,6 +61,7 @@
(define selected-rule #false)
(define output-format plain-text)
(define output-destination 'console)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax analyze"
Expand DownExpand Up@@ -105,6 +107,11 @@ changed relative to baseref are analyzed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--output-to-file"
outputpath
"Store results in a file instead of printing them to the console."
Expand All@@ -128,7 +135,8 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
#:targets (build-vector targets)
#:suite suite
#:output-format output-format
#:output-destination output-destination))
#:output-destination output-destination
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-fix-parse-command-line)
Expand All@@ -143,6 +151,7 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
(define max-pass-count 10)
(define max-modified-files +inf.0)
(define max-modified-lines +inf.0)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax fix"
Expand DownExpand Up@@ -197,6 +206,11 @@ changed relative to baseref are analyzed and fixed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--max-pass-count"
passcount
"The maximum number of times Resyntax will fix each file. By default, Resyntax runs at most 10 \
Expand DownExpand Up@@ -235,7 +249,8 @@ are needed when applying a fix unlocks further fixes."
#:max-fixes max-fixes
#:max-modified-files max-modified-files
#:max-modified-lines max-modified-lines
#:max-pass-count max-pass-count))
#:max-pass-count max-pass-count
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-run)
Expand DownExpand Up@@ -273,7 +288,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
(define analysis
(resyntax-analyze-all sources
#:suite (resyntax-analyze-options-suite options)
#:max-passes 1))
#:max-passes 1
#:timeout-ms (resyntax-analyze-options-analyzer-timeout-ms options)))
(define results
(transduce (resyntax-analysis-all-results analysis)
(append-mapping in-hash-values)
Expand DownExpand Up@@ -322,7 +338,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
#:max-fixes (resyntax-fix-options-max-fixes options)
#:max-passes (resyntax-fix-options-max-pass-count options)
#:max-modified-sources max-modified-files
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms (resyntax-fix-options-analyzer-timeout-ms options)))
(match fix-method
[(== modify-files)
(resyntax-analysis-write-file-changes! analysis)]
Expand Down
34 changes: 22 additions & 12 deletions main.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,17 +17,18 @@
[resyntax-analysis-write-file-changes! (-> resyntax-analysis? void?)]
[resyntax-analysis-commit-fixes! (-> resyntax-analysis? void?)]
[resyntax-analyze
(->* (source?) (#:suite refactoring-suite? #:lines range-set?) refactoring-result-set?)]
(->* (source?) (#:suite refactoring-suite? #:lines range-set? #:timeout-ms exact-nonnegative-integer?) refactoring-result-set?)]
[resyntax-analyze-all
(->* ((hash/c source? range-set? #:flat? #true))
(#:suite refactoring-suite?
#:max-fixes (or/c exact-nonnegative-integer? +inf.0)
#:max-passes exact-nonnegative-integer?
#:max-modified-sources (or/c exact-nonnegative-integer? +inf.0)
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0))
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0)
#:timeout-ms exact-nonnegative-integer?)
resyntax-analysis?)]
[reysntax-analyze-for-properties-only
(->* (source?) (#:suite refactoring-suite?) syntax-property-bundle?)]
(->* (source?) (#:suite refactoring-suite? #:timeout-ms exact-nonnegative-integer?) syntax-property-bundle?)]
[refactor! (-> (sequence/c refactoring-result?) void?)]))


Expand DownExpand Up@@ -167,7 +168,8 @@

(define/guard (resyntax-analyze source
#:suite [suite default-recommendations]
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define source-lang (source-read-language source))
(guard source-lang #:else
Expand DownExpand Up@@ -210,7 +212,8 @@
(with-handlers ([exn:fail? skip])
(define analysis (source-analyze source
#:lines lines
#:analyzers (refactoring-suite-analyzers effective-suite)))
#:analyzers (refactoring-suite-analyzers effective-suite)
#:timeout-ms timeout-ms))
(refactor-visited-forms
#:analysis analysis #:suite effective-suite #:comments comments #:lines lines)))

Expand All@@ -229,7 +232,9 @@
[else result-set]))


(define/guard (reysntax-analyze-for-properties-only source #:suite [suite default-recommendations])
(define/guard (reysntax-analyze-for-properties-only source
#:suite [suite default-recommendations]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define full-source (source->string source))
(guard (string-prefix? full-source "#lang racket") #:else
Expand All@@ -251,7 +256,8 @@
[exn:fail:filesystem:missing-module? skip]
[exn:fail:contract:variable? skip])
(define analysis (source-analyze source
#:analyzers (refactoring-suite-analyzers suite)))
#:analyzers (refactoring-suite-analyzers suite)
#:timeout-ms timeout-ms))
(source-code-analysis-added-syntax-properties analysis)))


Expand All@@ -260,7 +266,8 @@
#:max-fixes [max-fixes +inf.0]
#:max-passes [max-passes 10]
#:max-modified-sources [max-modified-sources +inf.0]
#:max-modified-lines [max-modified-lines +inf.0])
#:max-modified-lines [max-modified-lines +inf.0]
#:timeout-ms [timeout-ms 10000])
(log-resyntax-info "--- analyzing code ---")
(for/fold ([pass-result-lists '()]
[sources sources]
Expand All@@ -274,7 +281,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms))
(define pass-fix-count (count-total-results pass-results))
(define new-max-fixes (- max-fixes pass-fix-count))]
#:break (hash-empty? pass-results)
Expand All@@ -298,7 +306,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines)
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms)
(transduce (in-hash-entries sources) ; entries with source keys and line range set values

;; The following steps perform a kind of layered shuffle: the files to refactor are
Expand DownExpand Up@@ -326,7 +335,7 @@
(append-mapping
(λ (e)
(match-define (entry source lines) e)
(define result-set (resyntax-analyze source #:suite suite #:lines lines))
(define result-set (resyntax-analyze source #:suite suite #:lines lines #:timeout-ms timeout-ms))
(refactoring-result-set-results result-set)))
(limiting max-modified-lines
#:by (λ (result)
Expand DownExpand Up@@ -524,6 +533,7 @@
;; Test with multipass analyze
(define analysis
(resyntax-analyze-all (hash test-source (range-set (unbounded-range #:comparator natural<=>)))
#:suite breaking-suite))
#:suite breaking-suite
#:timeout-ms 10000))
(check-equal? (resyntax-analysis-total-fixes analysis) 0
"Breaking suggestions should be filtered from resyntax-analyze-all")))
43 changes: 19 additions & 24 deletions private/analysis.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@

(provide
(contract-out
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?))
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?) #:timeout-ms exact-nonnegative-integer?)
(#:lines range-set?)
source-code-analysis?)]
[source-code-analysis? (-> any/c boolean?)]
Expand DownExpand Up@@ -68,15 +68,9 @@
(syntax-ref stx path)))


;; Timeout for analyzers in seconds
(define analyzer-timeout-seconds 10)

;; Milliseconds per second (for time conversions)
(define milliseconds-per-second 1000)

;; Run an analyzer with a timeout. Returns the result or an empty syntax property bundle
;; if timeout occurred or an error was raised.
(define (run-analyzer-with-timeout analyzer expanded source-name)
(define (run-analyzer-with-timeout analyzer expanded source-name timeout-ms)
(define result-box (box #false))
(define error-box (box #false))
(define start-time (current-inexact-milliseconds))
Expand All@@ -87,8 +81,7 @@
(with-handlers ([exn:fail? (λ (e) (set-box! error-box e))])
(set-box! result-box (expansion-analyze analyzer expanded))))))

(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds)
(* analyzer-timeout-seconds milliseconds-per-second))))
(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds) timeout-ms)))

;; Wait for either completion or timeout
(define final-result
Expand All@@ -100,9 +93,9 @@
[(eq? final-result 'timeout)
(kill-thread analyzer-thread)
(log-resyntax-warning
"analyzer ~a timed out after ~a seconds while analyzing ~a"
"analyzer ~a timed out after ~a ms while analyzing ~a"
(object-name analyzer)
analyzer-timeout-seconds
timeout-ms
source-name)
(syntax-property-bundle)]
[else
Expand All@@ -125,7 +118,8 @@

(define (source-analyze code
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:analyzers analyzers)
#:analyzers analyzers
#:timeout-ms timeout-ms)
(define ns (make-base-namespace))
(parameterize ([current-directory (or (source-directory code) (current-directory))]
[current-namespace ns])
Expand DownExpand Up@@ -245,7 +239,7 @@
(transduce analyzers
(append-mapping
(λ (analyzer)
(define result (run-analyzer-with-timeout analyzer expanded program-source-name))
(define result (run-analyzer-with-timeout analyzer expanded program-source-name timeout-ms))
(syntax-property-bundle-entries result)))
(filtering
(λ (prop-entry)
Expand DownExpand Up@@ -312,20 +306,21 @@
(define test-source (string-source "#lang racket/base (define x 1)"))

;; Test with empty analyzers list
(define analysis-empty (source-analyze test-source #:analyzers '()))
(define analysis-empty (source-analyze test-source #:analyzers '() #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-empty))

;; Test with single analyzer
(define analysis-single
(source-analyze test-source #:analyzers (list identifier-usage-analyzer)))
(source-analyze test-source #:analyzers (list identifier-usage-analyzer) #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-single))

;; Test with default analyzers (should match default behavior)
(define analysis-default
(source-analyze test-source
#:analyzers (list identifier-usage-analyzer
ignored-result-values-analyzer
variable-mutability-analyzer)))
variable-mutability-analyzer)
#:timeout-ms 10000))
(check-true (source-code-analysis? analysis-default)))

(test-case "source-analyze filters out properties with invalid paths"
Expand All@@ -345,7 +340,7 @@
(syntax-property-entry (syntax-path (list 0 999)) 'another-invalid-prop #true)))))

;; Run analysis with the bad analyzer - should not crash
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed successfully
(check-true (source-code-analysis? analysis))
Expand All@@ -372,13 +367,13 @@
(make-expansion-analyzer
#:name 'slow-analyzer
(λ (expanded)
;; Sleep for 11 seconds - slightly longer than the 10 second timeout
(sleep 11)
;; Sleep for 200ms - longer than a 100ms timeout
(sleep 0.2)
(syntax-property-bundle
(syntax-property-entry empty-syntax-path 'slow-prop #true)))))

;; Run analysis with the slow analyzer - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer)))
;; Run analysis with the slow analyzer and a short timeout - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer) #:timeout-ms 100))

;; Check that the analysis completed (even though the analyzer timed out)
(check-true (source-code-analysis? analysis))
Expand All@@ -403,7 +398,7 @@
(syntax-property-entry empty-syntax-path 'fast-prop #true)))))

;; Run analysis with the fast analyzer - should complete successfully
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed
(check-true (source-code-analysis? analysis))
Expand All@@ -427,7 +422,7 @@
(error "intentional test error"))))

;; Run analysis with the failing analyzer - should skip it and not crash
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed (even though the analyzer failed)
(check-true (source-code-analysis? analysis))))
16 changes: 15 additions & 1 deletion test.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,7 +147,21 @@

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-line-mask)
#:with (value ...) (list #'line-set)))
#:with (value ...) (list #'line-set))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-analyzer-timeout-millis)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...)))
(#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-line-mask #'current-analyzer-timeout-millis)
#:with (value ...) (list #'line-set #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number)
(#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-analyzer-timeout-millis #'current-line-mask)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value) #'line-set)))

(define-splicing-syntax-class code-block-test-args
#:attributes ([check 1])
Expand Down
18 changes: 18 additions & 0 deletions test/analyzer-timeout-test.rkt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
#lang resyntax/test


header:
------------------------------
#lang racket/base
------------------------------


test: "timeout parameter can be customized in tests"
@analyzer-timeout-millis 5000
- (or 1 (or 2 3))
- (or 1 2 3)


no-change-test: "timeout parameter works with no-change-test"
@analyzer-timeout-millis 5000
- (define x 42)
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions cli.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@

(define-enum-type resyntax-output-format (plain-text github-pull-request-review git-commit-message json))
(define-enum-type resyntax-fix-method (modify-files create-multiple-git-commits))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination analyzer-timeout-ms))


(define-record-type resyntax-fix-options
Expand All@@ -48,7 +48,8 @@
max-fixes
max-modified-files
max-modified-lines
max-pass-count))
max-pass-count
analyzer-timeout-ms))


(define all-lines (range-set (unbounded-range #:comparator natural<=>)))
Expand All@@ -60,6 +61,7 @@
(define selected-rule #false)
(define output-format plain-text)
(define output-destination 'console)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax analyze"
Expand DownExpand Up@@ -105,6 +107,11 @@ changed relative to baseref are analyzed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--output-to-file"
outputpath
"Store results in a file instead of printing them to the console."
Expand All@@ -128,7 +135,8 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
#:targets (build-vector targets)
#:suite suite
#:output-format output-format
#:output-destination output-destination))
#:output-destination output-destination
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-fix-parse-command-line)
Expand All@@ -143,6 +151,7 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
(define max-pass-count 10)
(define max-modified-files +inf.0)
(define max-modified-lines +inf.0)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax fix"
Expand DownExpand Up@@ -197,6 +206,11 @@ changed relative to baseref are analyzed and fixed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--max-pass-count"
passcount
"The maximum number of times Resyntax will fix each file. By default, Resyntax runs at most 10 \
Expand DownExpand Up@@ -235,7 +249,8 @@ are needed when applying a fix unlocks further fixes."
#:max-fixes max-fixes
#:max-modified-files max-modified-files
#:max-modified-lines max-modified-lines
#:max-pass-count max-pass-count))
#:max-pass-count max-pass-count
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-run)
Expand DownExpand Up@@ -273,7 +288,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
(define analysis
(resyntax-analyze-all sources
#:suite (resyntax-analyze-options-suite options)
#:max-passes 1))
#:max-passes 1
#:timeout-ms (resyntax-analyze-options-analyzer-timeout-ms options)))
(define results
(transduce (resyntax-analysis-all-results analysis)
(append-mapping in-hash-values)
Expand DownExpand Up@@ -322,7 +338,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
#:max-fixes (resyntax-fix-options-max-fixes options)
#:max-passes (resyntax-fix-options-max-pass-count options)
#:max-modified-sources max-modified-files
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms (resyntax-fix-options-analyzer-timeout-ms options)))
(match fix-method
[(== modify-files)
(resyntax-analysis-write-file-changes! analysis)]
Expand Down
34 changes: 22 additions & 12 deletions main.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,17 +17,18 @@
[resyntax-analysis-write-file-changes! (-> resyntax-analysis? void?)]
[resyntax-analysis-commit-fixes! (-> resyntax-analysis? void?)]
[resyntax-analyze
(->* (source?) (#:suite refactoring-suite? #:lines range-set?) refactoring-result-set?)]
(->* (source?) (#:suite refactoring-suite? #:lines range-set? #:timeout-ms exact-nonnegative-integer?) refactoring-result-set?)]
[resyntax-analyze-all
(->* ((hash/c source? range-set? #:flat? #true))
(#:suite refactoring-suite?
#:max-fixes (or/c exact-nonnegative-integer? +inf.0)
#:max-passes exact-nonnegative-integer?
#:max-modified-sources (or/c exact-nonnegative-integer? +inf.0)
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0))
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0)
#:timeout-ms exact-nonnegative-integer?)
resyntax-analysis?)]
[reysntax-analyze-for-properties-only
(->* (source?) (#:suite refactoring-suite?) syntax-property-bundle?)]
(->* (source?) (#:suite refactoring-suite? #:timeout-ms exact-nonnegative-integer?) syntax-property-bundle?)]
[refactor! (-> (sequence/c refactoring-result?) void?)]))


Expand DownExpand Up@@ -167,7 +168,8 @@

(define/guard (resyntax-analyze source
#:suite [suite default-recommendations]
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define source-lang (source-read-language source))
(guard source-lang #:else
Expand DownExpand Up@@ -210,7 +212,8 @@
(with-handlers ([exn:fail? skip])
(define analysis (source-analyze source
#:lines lines
#:analyzers (refactoring-suite-analyzers effective-suite)))
#:analyzers (refactoring-suite-analyzers effective-suite)
#:timeout-ms timeout-ms))
(refactor-visited-forms
#:analysis analysis #:suite effective-suite #:comments comments #:lines lines)))

Expand All@@ -229,7 +232,9 @@
[else result-set]))


(define/guard (reysntax-analyze-for-properties-only source #:suite [suite default-recommendations])
(define/guard (reysntax-analyze-for-properties-only source
#:suite [suite default-recommendations]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define full-source (source->string source))
(guard (string-prefix? full-source "#lang racket") #:else
Expand All@@ -251,7 +256,8 @@
[exn:fail:filesystem:missing-module? skip]
[exn:fail:contract:variable? skip])
(define analysis (source-analyze source
#:analyzers (refactoring-suite-analyzers suite)))
#:analyzers (refactoring-suite-analyzers suite)
#:timeout-ms timeout-ms))
(source-code-analysis-added-syntax-properties analysis)))


Expand All@@ -260,7 +266,8 @@
#:max-fixes [max-fixes +inf.0]
#:max-passes [max-passes 10]
#:max-modified-sources [max-modified-sources +inf.0]
#:max-modified-lines [max-modified-lines +inf.0])
#:max-modified-lines [max-modified-lines +inf.0]
#:timeout-ms [timeout-ms 10000])
(log-resyntax-info "--- analyzing code ---")
(for/fold ([pass-result-lists '()]
[sources sources]
Expand All@@ -274,7 +281,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms))
(define pass-fix-count (count-total-results pass-results))
(define new-max-fixes (- max-fixes pass-fix-count))]
#:break (hash-empty? pass-results)
Expand All@@ -298,7 +306,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines)
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms)
(transduce (in-hash-entries sources) ; entries with source keys and line range set values

;; The following steps perform a kind of layered shuffle: the files to refactor are
Expand DownExpand Up@@ -326,7 +335,7 @@
(append-mapping
(λ (e)
(match-define (entry source lines) e)
(define result-set (resyntax-analyze source #:suite suite #:lines lines))
(define result-set (resyntax-analyze source #:suite suite #:lines lines #:timeout-ms timeout-ms))
(refactoring-result-set-results result-set)))
(limiting max-modified-lines
#:by (λ (result)
Expand DownExpand Up@@ -524,6 +533,7 @@
;; Test with multipass analyze
(define analysis
(resyntax-analyze-all (hash test-source (range-set (unbounded-range #:comparator natural<=>)))
#:suite breaking-suite))
#:suite breaking-suite
#:timeout-ms 10000))
(check-equal? (resyntax-analysis-total-fixes analysis) 0
"Breaking suggestions should be filtered from resyntax-analyze-all")))
43 changes: 19 additions & 24 deletions private/analysis.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@

(provide
(contract-out
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?))
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?) #:timeout-ms exact-nonnegative-integer?)
(#:lines range-set?)
source-code-analysis?)]
[source-code-analysis? (-> any/c boolean?)]
Expand DownExpand Up@@ -68,15 +68,9 @@
(syntax-ref stx path)))


;; Timeout for analyzers in seconds
(define analyzer-timeout-seconds 10)

;; Milliseconds per second (for time conversions)
(define milliseconds-per-second 1000)

;; Run an analyzer with a timeout. Returns the result or an empty syntax property bundle
;; if timeout occurred or an error was raised.
(define (run-analyzer-with-timeout analyzer expanded source-name)
(define (run-analyzer-with-timeout analyzer expanded source-name timeout-ms)
(define result-box (box #false))
(define error-box (box #false))
(define start-time (current-inexact-milliseconds))
Expand All@@ -87,8 +81,7 @@
(with-handlers ([exn:fail? (λ (e) (set-box! error-box e))])
(set-box! result-box (expansion-analyze analyzer expanded))))))

(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds)
(* analyzer-timeout-seconds milliseconds-per-second))))
(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds) timeout-ms)))

;; Wait for either completion or timeout
(define final-result
Expand All@@ -100,9 +93,9 @@
[(eq? final-result 'timeout)
(kill-thread analyzer-thread)
(log-resyntax-warning
"analyzer ~a timed out after ~a seconds while analyzing ~a"
"analyzer ~a timed out after ~a ms while analyzing ~a"
(object-name analyzer)
analyzer-timeout-seconds
timeout-ms
source-name)
(syntax-property-bundle)]
[else
Expand All@@ -125,7 +118,8 @@

(define (source-analyze code
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:analyzers analyzers)
#:analyzers analyzers
#:timeout-ms timeout-ms)
(define ns (make-base-namespace))
(parameterize ([current-directory (or (source-directory code) (current-directory))]
[current-namespace ns])
Expand DownExpand Up@@ -245,7 +239,7 @@
(transduce analyzers
(append-mapping
(λ (analyzer)
(define result (run-analyzer-with-timeout analyzer expanded program-source-name))
(define result (run-analyzer-with-timeout analyzer expanded program-source-name timeout-ms))
(syntax-property-bundle-entries result)))
(filtering
(λ (prop-entry)
Expand DownExpand Up@@ -312,20 +306,21 @@
(define test-source (string-source "#lang racket/base (define x 1)"))

;; Test with empty analyzers list
(define analysis-empty (source-analyze test-source #:analyzers '()))
(define analysis-empty (source-analyze test-source #:analyzers '() #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-empty))

;; Test with single analyzer
(define analysis-single
(source-analyze test-source #:analyzers (list identifier-usage-analyzer)))
(source-analyze test-source #:analyzers (list identifier-usage-analyzer) #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-single))

;; Test with default analyzers (should match default behavior)
(define analysis-default
(source-analyze test-source
#:analyzers (list identifier-usage-analyzer
ignored-result-values-analyzer
variable-mutability-analyzer)))
variable-mutability-analyzer)
#:timeout-ms 10000))
(check-true (source-code-analysis? analysis-default)))

(test-case "source-analyze filters out properties with invalid paths"
Expand All@@ -345,7 +340,7 @@
(syntax-property-entry (syntax-path (list 0 999)) 'another-invalid-prop #true)))))

;; Run analysis with the bad analyzer - should not crash
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed successfully
(check-true (source-code-analysis? analysis))
Expand All@@ -372,13 +367,13 @@
(make-expansion-analyzer
#:name 'slow-analyzer
(λ (expanded)
;; Sleep for 11 seconds - slightly longer than the 10 second timeout
(sleep 11)
;; Sleep for 200ms - longer than a 100ms timeout
(sleep 0.2)
(syntax-property-bundle
(syntax-property-entry empty-syntax-path 'slow-prop #true)))))

;; Run analysis with the slow analyzer - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer)))
;; Run analysis with the slow analyzer and a short timeout - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer) #:timeout-ms 100))

;; Check that the analysis completed (even though the analyzer timed out)
(check-true (source-code-analysis? analysis))
Expand All@@ -403,7 +398,7 @@
(syntax-property-entry empty-syntax-path 'fast-prop #true)))))

;; Run analysis with the fast analyzer - should complete successfully
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed
(check-true (source-code-analysis? analysis))
Expand All@@ -427,7 +422,7 @@
(error "intentional test error"))))

;; Run analysis with the failing analyzer - should skip it and not crash
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed (even though the analyzer failed)
(check-true (source-code-analysis? analysis))))
16 changes: 15 additions & 1 deletion test.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,7 +147,21 @@

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-line-mask)
#:with (value ...) (list #'line-set)))
#:with (value ...) (list #'line-set))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-analyzer-timeout-millis)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...)))
(#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-line-mask #'current-analyzer-timeout-millis)
#:with (value ...) (list #'line-set #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number)
(#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-analyzer-timeout-millis #'current-line-mask)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value) #'line-set)))

(define-splicing-syntax-class code-block-test-args
#:attributes ([check 1])
Expand Down
18 changes: 18 additions & 0 deletions test/analyzer-timeout-test.rkt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
#lang resyntax/test


header:
------------------------------
#lang racket/base
------------------------------


test: "timeout parameter can be customized in tests"
@analyzer-timeout-millis 5000
- (or 1 (or 2 3))
- (or 1 2 3)


no-change-test: "timeout parameter works with no-change-test"
@analyzer-timeout-millis 5000
- (define x 42)
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions cli.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@

(define-enum-type resyntax-output-format (plain-text github-pull-request-review git-commit-message json))
(define-enum-type resyntax-fix-method (modify-files create-multiple-git-commits))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination analyzer-timeout-ms))


(define-record-type resyntax-fix-options
Expand All@@ -48,7 +48,8 @@
max-fixes
max-modified-files
max-modified-lines
max-pass-count))
max-pass-count
analyzer-timeout-ms))


(define all-lines (range-set (unbounded-range #:comparator natural<=>)))
Expand All@@ -60,6 +61,7 @@
(define selected-rule #false)
(define output-format plain-text)
(define output-destination 'console)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax analyze"
Expand DownExpand Up@@ -105,6 +107,11 @@ changed relative to baseref are analyzed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--output-to-file"
outputpath
"Store results in a file instead of printing them to the console."
Expand All@@ -128,7 +135,8 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
#:targets (build-vector targets)
#:suite suite
#:output-format output-format
#:output-destination output-destination))
#:output-destination output-destination
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-fix-parse-command-line)
Expand All@@ -143,6 +151,7 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
(define max-pass-count 10)
(define max-modified-files +inf.0)
(define max-modified-lines +inf.0)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax fix"
Expand DownExpand Up@@ -197,6 +206,11 @@ changed relative to baseref are analyzed and fixed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--max-pass-count"
passcount
"The maximum number of times Resyntax will fix each file. By default, Resyntax runs at most 10 \
Expand DownExpand Up@@ -235,7 +249,8 @@ are needed when applying a fix unlocks further fixes."
#:max-fixes max-fixes
#:max-modified-files max-modified-files
#:max-modified-lines max-modified-lines
#:max-pass-count max-pass-count))
#:max-pass-count max-pass-count
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-run)
Expand DownExpand Up@@ -273,7 +288,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
(define analysis
(resyntax-analyze-all sources
#:suite (resyntax-analyze-options-suite options)
#:max-passes 1))
#:max-passes 1
#:timeout-ms (resyntax-analyze-options-analyzer-timeout-ms options)))
(define results
(transduce (resyntax-analysis-all-results analysis)
(append-mapping in-hash-values)
Expand DownExpand Up@@ -322,7 +338,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
#:max-fixes (resyntax-fix-options-max-fixes options)
#:max-passes (resyntax-fix-options-max-pass-count options)
#:max-modified-sources max-modified-files
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms (resyntax-fix-options-analyzer-timeout-ms options)))
(match fix-method
[(== modify-files)
(resyntax-analysis-write-file-changes! analysis)]
Expand Down
34 changes: 22 additions & 12 deletions main.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,17 +17,18 @@
[resyntax-analysis-write-file-changes! (-> resyntax-analysis? void?)]
[resyntax-analysis-commit-fixes! (-> resyntax-analysis? void?)]
[resyntax-analyze
(->* (source?) (#:suite refactoring-suite? #:lines range-set?) refactoring-result-set?)]
(->* (source?) (#:suite refactoring-suite? #:lines range-set? #:timeout-ms exact-nonnegative-integer?) refactoring-result-set?)]
[resyntax-analyze-all
(->* ((hash/c source? range-set? #:flat? #true))
(#:suite refactoring-suite?
#:max-fixes (or/c exact-nonnegative-integer? +inf.0)
#:max-passes exact-nonnegative-integer?
#:max-modified-sources (or/c exact-nonnegative-integer? +inf.0)
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0))
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0)
#:timeout-ms exact-nonnegative-integer?)
resyntax-analysis?)]
[reysntax-analyze-for-properties-only
(->* (source?) (#:suite refactoring-suite?) syntax-property-bundle?)]
(->* (source?) (#:suite refactoring-suite? #:timeout-ms exact-nonnegative-integer?) syntax-property-bundle?)]
[refactor! (-> (sequence/c refactoring-result?) void?)]))


Expand DownExpand Up@@ -167,7 +168,8 @@

(define/guard (resyntax-analyze source
#:suite [suite default-recommendations]
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define source-lang (source-read-language source))
(guard source-lang #:else
Expand DownExpand Up@@ -210,7 +212,8 @@
(with-handlers ([exn:fail? skip])
(define analysis (source-analyze source
#:lines lines
#:analyzers (refactoring-suite-analyzers effective-suite)))
#:analyzers (refactoring-suite-analyzers effective-suite)
#:timeout-ms timeout-ms))
(refactor-visited-forms
#:analysis analysis #:suite effective-suite #:comments comments #:lines lines)))

Expand All@@ -229,7 +232,9 @@
[else result-set]))


(define/guard (reysntax-analyze-for-properties-only source #:suite [suite default-recommendations])
(define/guard (reysntax-analyze-for-properties-only source
#:suite [suite default-recommendations]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define full-source (source->string source))
(guard (string-prefix? full-source "#lang racket") #:else
Expand All@@ -251,7 +256,8 @@
[exn:fail:filesystem:missing-module? skip]
[exn:fail:contract:variable? skip])
(define analysis (source-analyze source
#:analyzers (refactoring-suite-analyzers suite)))
#:analyzers (refactoring-suite-analyzers suite)
#:timeout-ms timeout-ms))
(source-code-analysis-added-syntax-properties analysis)))


Expand All@@ -260,7 +266,8 @@
#:max-fixes [max-fixes +inf.0]
#:max-passes [max-passes 10]
#:max-modified-sources [max-modified-sources +inf.0]
#:max-modified-lines [max-modified-lines +inf.0])
#:max-modified-lines [max-modified-lines +inf.0]
#:timeout-ms [timeout-ms 10000])
(log-resyntax-info "--- analyzing code ---")
(for/fold ([pass-result-lists '()]
[sources sources]
Expand All@@ -274,7 +281,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms))
(define pass-fix-count (count-total-results pass-results))
(define new-max-fixes (- max-fixes pass-fix-count))]
#:break (hash-empty? pass-results)
Expand All@@ -298,7 +306,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines)
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms)
(transduce (in-hash-entries sources) ; entries with source keys and line range set values

;; The following steps perform a kind of layered shuffle: the files to refactor are
Expand DownExpand Up@@ -326,7 +335,7 @@
(append-mapping
(λ (e)
(match-define (entry source lines) e)
(define result-set (resyntax-analyze source #:suite suite #:lines lines))
(define result-set (resyntax-analyze source #:suite suite #:lines lines #:timeout-ms timeout-ms))
(refactoring-result-set-results result-set)))
(limiting max-modified-lines
#:by (λ (result)
Expand DownExpand Up@@ -524,6 +533,7 @@
;; Test with multipass analyze
(define analysis
(resyntax-analyze-all (hash test-source (range-set (unbounded-range #:comparator natural<=>)))
#:suite breaking-suite))
#:suite breaking-suite
#:timeout-ms 10000))
(check-equal? (resyntax-analysis-total-fixes analysis) 0
"Breaking suggestions should be filtered from resyntax-analyze-all")))
43 changes: 19 additions & 24 deletions private/analysis.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@

(provide
(contract-out
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?))
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?) #:timeout-ms exact-nonnegative-integer?)
(#:lines range-set?)
source-code-analysis?)]
[source-code-analysis? (-> any/c boolean?)]
Expand DownExpand Up@@ -68,15 +68,9 @@
(syntax-ref stx path)))


;; Timeout for analyzers in seconds
(define analyzer-timeout-seconds 10)

;; Milliseconds per second (for time conversions)
(define milliseconds-per-second 1000)

;; Run an analyzer with a timeout. Returns the result or an empty syntax property bundle
;; if timeout occurred or an error was raised.
(define (run-analyzer-with-timeout analyzer expanded source-name)
(define (run-analyzer-with-timeout analyzer expanded source-name timeout-ms)
(define result-box (box #false))
(define error-box (box #false))
(define start-time (current-inexact-milliseconds))
Expand All@@ -87,8 +81,7 @@
(with-handlers ([exn:fail? (λ (e) (set-box! error-box e))])
(set-box! result-box (expansion-analyze analyzer expanded))))))

(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds)
(* analyzer-timeout-seconds milliseconds-per-second))))
(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds) timeout-ms)))

;; Wait for either completion or timeout
(define final-result
Expand All@@ -100,9 +93,9 @@
[(eq? final-result 'timeout)
(kill-thread analyzer-thread)
(log-resyntax-warning
"analyzer ~a timed out after ~a seconds while analyzing ~a"
"analyzer ~a timed out after ~a ms while analyzing ~a"
(object-name analyzer)
analyzer-timeout-seconds
timeout-ms
source-name)
(syntax-property-bundle)]
[else
Expand All@@ -125,7 +118,8 @@

(define (source-analyze code
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:analyzers analyzers)
#:analyzers analyzers
#:timeout-ms timeout-ms)
(define ns (make-base-namespace))
(parameterize ([current-directory (or (source-directory code) (current-directory))]
[current-namespace ns])
Expand DownExpand Up@@ -245,7 +239,7 @@
(transduce analyzers
(append-mapping
(λ (analyzer)
(define result (run-analyzer-with-timeout analyzer expanded program-source-name))
(define result (run-analyzer-with-timeout analyzer expanded program-source-name timeout-ms))
(syntax-property-bundle-entries result)))
(filtering
(λ (prop-entry)
Expand DownExpand Up@@ -312,20 +306,21 @@
(define test-source (string-source "#lang racket/base (define x 1)"))

;; Test with empty analyzers list
(define analysis-empty (source-analyze test-source #:analyzers '()))
(define analysis-empty (source-analyze test-source #:analyzers '() #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-empty))

;; Test with single analyzer
(define analysis-single
(source-analyze test-source #:analyzers (list identifier-usage-analyzer)))
(source-analyze test-source #:analyzers (list identifier-usage-analyzer) #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-single))

;; Test with default analyzers (should match default behavior)
(define analysis-default
(source-analyze test-source
#:analyzers (list identifier-usage-analyzer
ignored-result-values-analyzer
variable-mutability-analyzer)))
variable-mutability-analyzer)
#:timeout-ms 10000))
(check-true (source-code-analysis? analysis-default)))

(test-case "source-analyze filters out properties with invalid paths"
Expand All@@ -345,7 +340,7 @@
(syntax-property-entry (syntax-path (list 0 999)) 'another-invalid-prop #true)))))

;; Run analysis with the bad analyzer - should not crash
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed successfully
(check-true (source-code-analysis? analysis))
Expand All@@ -372,13 +367,13 @@
(make-expansion-analyzer
#:name 'slow-analyzer
(λ (expanded)
;; Sleep for 11 seconds - slightly longer than the 10 second timeout
(sleep 11)
;; Sleep for 200ms - longer than a 100ms timeout
(sleep 0.2)
(syntax-property-bundle
(syntax-property-entry empty-syntax-path 'slow-prop #true)))))

;; Run analysis with the slow analyzer - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer)))
;; Run analysis with the slow analyzer and a short timeout - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer) #:timeout-ms 100))

;; Check that the analysis completed (even though the analyzer timed out)
(check-true (source-code-analysis? analysis))
Expand All@@ -403,7 +398,7 @@
(syntax-property-entry empty-syntax-path 'fast-prop #true)))))

;; Run analysis with the fast analyzer - should complete successfully
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed
(check-true (source-code-analysis? analysis))
Expand All@@ -427,7 +422,7 @@
(error "intentional test error"))))

;; Run analysis with the failing analyzer - should skip it and not crash
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed (even though the analyzer failed)
(check-true (source-code-analysis? analysis))))
16 changes: 15 additions & 1 deletion test.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,7 +147,21 @@

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-line-mask)
#:with (value ...) (list #'line-set)))
#:with (value ...) (list #'line-set))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-analyzer-timeout-millis)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...)))
(#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-line-mask #'current-analyzer-timeout-millis)
#:with (value ...) (list #'line-set #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number)
(#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-analyzer-timeout-millis #'current-line-mask)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value) #'line-set)))

(define-splicing-syntax-class code-block-test-args
#:attributes ([check 1])
Expand Down
18 changes: 18 additions & 0 deletions test/analyzer-timeout-test.rkt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
#lang resyntax/test


header:
------------------------------
#lang racket/base
------------------------------


test: "timeout parameter can be customized in tests"
@analyzer-timeout-millis 5000
- (or 1 (or 2 3))
- (or 1 2 3)


no-change-test: "timeout parameter works with no-change-test"
@analyzer-timeout-millis 5000
- (define x 42)
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions cli.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@

(define-enum-type resyntax-output-format (plain-text github-pull-request-review git-commit-message json))
(define-enum-type resyntax-fix-method (modify-files create-multiple-git-commits))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination analyzer-timeout-ms))


(define-record-type resyntax-fix-options
Expand All@@ -48,7 +48,8 @@
max-fixes
max-modified-files
max-modified-lines
max-pass-count))
max-pass-count
analyzer-timeout-ms))


(define all-lines (range-set (unbounded-range #:comparator natural<=>)))
Expand All@@ -60,6 +61,7 @@
(define selected-rule #false)
(define output-format plain-text)
(define output-destination 'console)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax analyze"
Expand DownExpand Up@@ -105,6 +107,11 @@ changed relative to baseref are analyzed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--output-to-file"
outputpath
"Store results in a file instead of printing them to the console."
Expand All@@ -128,7 +135,8 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
#:targets (build-vector targets)
#:suite suite
#:output-format output-format
#:output-destination output-destination))
#:output-destination output-destination
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-fix-parse-command-line)
Expand All@@ -143,6 +151,7 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
(define max-pass-count 10)
(define max-modified-files +inf.0)
(define max-modified-lines +inf.0)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax fix"
Expand DownExpand Up@@ -197,6 +206,11 @@ changed relative to baseref are analyzed and fixed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--max-pass-count"
passcount
"The maximum number of times Resyntax will fix each file. By default, Resyntax runs at most 10 \
Expand DownExpand Up@@ -235,7 +249,8 @@ are needed when applying a fix unlocks further fixes."
#:max-fixes max-fixes
#:max-modified-files max-modified-files
#:max-modified-lines max-modified-lines
#:max-pass-count max-pass-count))
#:max-pass-count max-pass-count
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-run)
Expand DownExpand Up@@ -273,7 +288,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
(define analysis
(resyntax-analyze-all sources
#:suite (resyntax-analyze-options-suite options)
#:max-passes 1))
#:max-passes 1
#:timeout-ms (resyntax-analyze-options-analyzer-timeout-ms options)))
(define results
(transduce (resyntax-analysis-all-results analysis)
(append-mapping in-hash-values)
Expand DownExpand Up@@ -322,7 +338,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
#:max-fixes (resyntax-fix-options-max-fixes options)
#:max-passes (resyntax-fix-options-max-pass-count options)
#:max-modified-sources max-modified-files
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms (resyntax-fix-options-analyzer-timeout-ms options)))
(match fix-method
[(== modify-files)
(resyntax-analysis-write-file-changes! analysis)]
Expand Down
34 changes: 22 additions & 12 deletions main.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,17 +17,18 @@
[resyntax-analysis-write-file-changes! (-> resyntax-analysis? void?)]
[resyntax-analysis-commit-fixes! (-> resyntax-analysis? void?)]
[resyntax-analyze
(->* (source?) (#:suite refactoring-suite? #:lines range-set?) refactoring-result-set?)]
(->* (source?) (#:suite refactoring-suite? #:lines range-set? #:timeout-ms exact-nonnegative-integer?) refactoring-result-set?)]
[resyntax-analyze-all
(->* ((hash/c source? range-set? #:flat? #true))
(#:suite refactoring-suite?
#:max-fixes (or/c exact-nonnegative-integer? +inf.0)
#:max-passes exact-nonnegative-integer?
#:max-modified-sources (or/c exact-nonnegative-integer? +inf.0)
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0))
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0)
#:timeout-ms exact-nonnegative-integer?)
resyntax-analysis?)]
[reysntax-analyze-for-properties-only
(->* (source?) (#:suite refactoring-suite?) syntax-property-bundle?)]
(->* (source?) (#:suite refactoring-suite? #:timeout-ms exact-nonnegative-integer?) syntax-property-bundle?)]
[refactor! (-> (sequence/c refactoring-result?) void?)]))


Expand DownExpand Up@@ -167,7 +168,8 @@

(define/guard (resyntax-analyze source
#:suite [suite default-recommendations]
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define source-lang (source-read-language source))
(guard source-lang #:else
Expand DownExpand Up@@ -210,7 +212,8 @@
(with-handlers ([exn:fail? skip])
(define analysis (source-analyze source
#:lines lines
#:analyzers (refactoring-suite-analyzers effective-suite)))
#:analyzers (refactoring-suite-analyzers effective-suite)
#:timeout-ms timeout-ms))
(refactor-visited-forms
#:analysis analysis #:suite effective-suite #:comments comments #:lines lines)))

Expand All@@ -229,7 +232,9 @@
[else result-set]))


(define/guard (reysntax-analyze-for-properties-only source #:suite [suite default-recommendations])
(define/guard (reysntax-analyze-for-properties-only source
#:suite [suite default-recommendations]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define full-source (source->string source))
(guard (string-prefix? full-source "#lang racket") #:else
Expand All@@ -251,7 +256,8 @@
[exn:fail:filesystem:missing-module? skip]
[exn:fail:contract:variable? skip])
(define analysis (source-analyze source
#:analyzers (refactoring-suite-analyzers suite)))
#:analyzers (refactoring-suite-analyzers suite)
#:timeout-ms timeout-ms))
(source-code-analysis-added-syntax-properties analysis)))


Expand All@@ -260,7 +266,8 @@
#:max-fixes [max-fixes +inf.0]
#:max-passes [max-passes 10]
#:max-modified-sources [max-modified-sources +inf.0]
#:max-modified-lines [max-modified-lines +inf.0])
#:max-modified-lines [max-modified-lines +inf.0]
#:timeout-ms [timeout-ms 10000])
(log-resyntax-info "--- analyzing code ---")
(for/fold ([pass-result-lists '()]
[sources sources]
Expand All@@ -274,7 +281,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms))
(define pass-fix-count (count-total-results pass-results))
(define new-max-fixes (- max-fixes pass-fix-count))]
#:break (hash-empty? pass-results)
Expand All@@ -298,7 +306,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines)
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms)
(transduce (in-hash-entries sources) ; entries with source keys and line range set values

;; The following steps perform a kind of layered shuffle: the files to refactor are
Expand DownExpand Up@@ -326,7 +335,7 @@
(append-mapping
(λ (e)
(match-define (entry source lines) e)
(define result-set (resyntax-analyze source #:suite suite #:lines lines))
(define result-set (resyntax-analyze source #:suite suite #:lines lines #:timeout-ms timeout-ms))
(refactoring-result-set-results result-set)))
(limiting max-modified-lines
#:by (λ (result)
Expand DownExpand Up@@ -524,6 +533,7 @@
;; Test with multipass analyze
(define analysis
(resyntax-analyze-all (hash test-source (range-set (unbounded-range #:comparator natural<=>)))
#:suite breaking-suite))
#:suite breaking-suite
#:timeout-ms 10000))
(check-equal? (resyntax-analysis-total-fixes analysis) 0
"Breaking suggestions should be filtered from resyntax-analyze-all")))
43 changes: 19 additions & 24 deletions private/analysis.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@

(provide
(contract-out
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?))
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?) #:timeout-ms exact-nonnegative-integer?)
(#:lines range-set?)
source-code-analysis?)]
[source-code-analysis? (-> any/c boolean?)]
Expand DownExpand Up@@ -68,15 +68,9 @@
(syntax-ref stx path)))


;; Timeout for analyzers in seconds
(define analyzer-timeout-seconds 10)

;; Milliseconds per second (for time conversions)
(define milliseconds-per-second 1000)

;; Run an analyzer with a timeout. Returns the result or an empty syntax property bundle
;; if timeout occurred or an error was raised.
(define (run-analyzer-with-timeout analyzer expanded source-name)
(define (run-analyzer-with-timeout analyzer expanded source-name timeout-ms)
(define result-box (box #false))
(define error-box (box #false))
(define start-time (current-inexact-milliseconds))
Expand All@@ -87,8 +81,7 @@
(with-handlers ([exn:fail? (λ (e) (set-box! error-box e))])
(set-box! result-box (expansion-analyze analyzer expanded))))))

(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds)
(* analyzer-timeout-seconds milliseconds-per-second))))
(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds) timeout-ms)))

;; Wait for either completion or timeout
(define final-result
Expand All@@ -100,9 +93,9 @@
[(eq? final-result 'timeout)
(kill-thread analyzer-thread)
(log-resyntax-warning
"analyzer ~a timed out after ~a seconds while analyzing ~a"
"analyzer ~a timed out after ~a ms while analyzing ~a"
(object-name analyzer)
analyzer-timeout-seconds
timeout-ms
source-name)
(syntax-property-bundle)]
[else
Expand All@@ -125,7 +118,8 @@

(define (source-analyze code
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:analyzers analyzers)
#:analyzers analyzers
#:timeout-ms timeout-ms)
(define ns (make-base-namespace))
(parameterize ([current-directory (or (source-directory code) (current-directory))]
[current-namespace ns])
Expand DownExpand Up@@ -245,7 +239,7 @@
(transduce analyzers
(append-mapping
(λ (analyzer)
(define result (run-analyzer-with-timeout analyzer expanded program-source-name))
(define result (run-analyzer-with-timeout analyzer expanded program-source-name timeout-ms))
(syntax-property-bundle-entries result)))
(filtering
(λ (prop-entry)
Expand DownExpand Up@@ -312,20 +306,21 @@
(define test-source (string-source "#lang racket/base (define x 1)"))

;; Test with empty analyzers list
(define analysis-empty (source-analyze test-source #:analyzers '()))
(define analysis-empty (source-analyze test-source #:analyzers '() #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-empty))

;; Test with single analyzer
(define analysis-single
(source-analyze test-source #:analyzers (list identifier-usage-analyzer)))
(source-analyze test-source #:analyzers (list identifier-usage-analyzer) #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-single))

;; Test with default analyzers (should match default behavior)
(define analysis-default
(source-analyze test-source
#:analyzers (list identifier-usage-analyzer
ignored-result-values-analyzer
variable-mutability-analyzer)))
variable-mutability-analyzer)
#:timeout-ms 10000))
(check-true (source-code-analysis? analysis-default)))

(test-case "source-analyze filters out properties with invalid paths"
Expand All@@ -345,7 +340,7 @@
(syntax-property-entry (syntax-path (list 0 999)) 'another-invalid-prop #true)))))

;; Run analysis with the bad analyzer - should not crash
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed successfully
(check-true (source-code-analysis? analysis))
Expand All@@ -372,13 +367,13 @@
(make-expansion-analyzer
#:name 'slow-analyzer
(λ (expanded)
;; Sleep for 11 seconds - slightly longer than the 10 second timeout
(sleep 11)
;; Sleep for 200ms - longer than a 100ms timeout
(sleep 0.2)
(syntax-property-bundle
(syntax-property-entry empty-syntax-path 'slow-prop #true)))))

;; Run analysis with the slow analyzer - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer)))
;; Run analysis with the slow analyzer and a short timeout - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer) #:timeout-ms 100))

;; Check that the analysis completed (even though the analyzer timed out)
(check-true (source-code-analysis? analysis))
Expand All@@ -403,7 +398,7 @@
(syntax-property-entry empty-syntax-path 'fast-prop #true)))))

;; Run analysis with the fast analyzer - should complete successfully
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed
(check-true (source-code-analysis? analysis))
Expand All@@ -427,7 +422,7 @@
(error "intentional test error"))))

;; Run analysis with the failing analyzer - should skip it and not crash
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed (even though the analyzer failed)
(check-true (source-code-analysis? analysis))))
16 changes: 15 additions & 1 deletion test.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,7 +147,21 @@

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-line-mask)
#:with (value ...) (list #'line-set)))
#:with (value ...) (list #'line-set))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-analyzer-timeout-millis)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...)))
(#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-line-mask #'current-analyzer-timeout-millis)
#:with (value ...) (list #'line-set #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number)
(#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-analyzer-timeout-millis #'current-line-mask)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value) #'line-set)))

(define-splicing-syntax-class code-block-test-args
#:attributes ([check 1])
Expand Down
18 changes: 18 additions & 0 deletions test/analyzer-timeout-test.rkt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
#lang resyntax/test


header:
------------------------------
#lang racket/base
------------------------------


test: "timeout parameter can be customized in tests"
@analyzer-timeout-millis 5000
- (or 1 (or 2 3))
- (or 1 2 3)


no-change-test: "timeout parameter works with no-change-test"
@analyzer-timeout-millis 5000
- (define x 42)
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions cli.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@

(define-enum-type resyntax-output-format (plain-text github-pull-request-review git-commit-message json))
(define-enum-type resyntax-fix-method (modify-files create-multiple-git-commits))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination analyzer-timeout-ms))


(define-record-type resyntax-fix-options
Expand All@@ -48,7 +48,8 @@
max-fixes
max-modified-files
max-modified-lines
max-pass-count))
max-pass-count
analyzer-timeout-ms))


(define all-lines (range-set (unbounded-range #:comparator natural<=>)))
Expand All@@ -60,6 +61,7 @@
(define selected-rule #false)
(define output-format plain-text)
(define output-destination 'console)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax analyze"
Expand DownExpand Up@@ -105,6 +107,11 @@ changed relative to baseref are analyzed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--output-to-file"
outputpath
"Store results in a file instead of printing them to the console."
Expand All@@ -128,7 +135,8 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
#:targets (build-vector targets)
#:suite suite
#:output-format output-format
#:output-destination output-destination))
#:output-destination output-destination
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-fix-parse-command-line)
Expand All@@ -143,6 +151,7 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
(define max-pass-count 10)
(define max-modified-files +inf.0)
(define max-modified-lines +inf.0)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax fix"
Expand DownExpand Up@@ -197,6 +206,11 @@ changed relative to baseref are analyzed and fixed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--max-pass-count"
passcount
"The maximum number of times Resyntax will fix each file. By default, Resyntax runs at most 10 \
Expand DownExpand Up@@ -235,7 +249,8 @@ are needed when applying a fix unlocks further fixes."
#:max-fixes max-fixes
#:max-modified-files max-modified-files
#:max-modified-lines max-modified-lines
#:max-pass-count max-pass-count))
#:max-pass-count max-pass-count
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-run)
Expand DownExpand Up@@ -273,7 +288,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
(define analysis
(resyntax-analyze-all sources
#:suite (resyntax-analyze-options-suite options)
#:max-passes 1))
#:max-passes 1
#:timeout-ms (resyntax-analyze-options-analyzer-timeout-ms options)))
(define results
(transduce (resyntax-analysis-all-results analysis)
(append-mapping in-hash-values)
Expand DownExpand Up@@ -322,7 +338,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
#:max-fixes (resyntax-fix-options-max-fixes options)
#:max-passes (resyntax-fix-options-max-pass-count options)
#:max-modified-sources max-modified-files
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms (resyntax-fix-options-analyzer-timeout-ms options)))
(match fix-method
[(== modify-files)
(resyntax-analysis-write-file-changes! analysis)]
Expand Down
34 changes: 22 additions & 12 deletions main.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,17 +17,18 @@
[resyntax-analysis-write-file-changes! (-> resyntax-analysis? void?)]
[resyntax-analysis-commit-fixes! (-> resyntax-analysis? void?)]
[resyntax-analyze
(->* (source?) (#:suite refactoring-suite? #:lines range-set?) refactoring-result-set?)]
(->* (source?) (#:suite refactoring-suite? #:lines range-set? #:timeout-ms exact-nonnegative-integer?) refactoring-result-set?)]
[resyntax-analyze-all
(->* ((hash/c source? range-set? #:flat? #true))
(#:suite refactoring-suite?
#:max-fixes (or/c exact-nonnegative-integer? +inf.0)
#:max-passes exact-nonnegative-integer?
#:max-modified-sources (or/c exact-nonnegative-integer? +inf.0)
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0))
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0)
#:timeout-ms exact-nonnegative-integer?)
resyntax-analysis?)]
[reysntax-analyze-for-properties-only
(->* (source?) (#:suite refactoring-suite?) syntax-property-bundle?)]
(->* (source?) (#:suite refactoring-suite? #:timeout-ms exact-nonnegative-integer?) syntax-property-bundle?)]
[refactor! (-> (sequence/c refactoring-result?) void?)]))


Expand DownExpand Up@@ -167,7 +168,8 @@

(define/guard (resyntax-analyze source
#:suite [suite default-recommendations]
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define source-lang (source-read-language source))
(guard source-lang #:else
Expand DownExpand Up@@ -210,7 +212,8 @@
(with-handlers ([exn:fail? skip])
(define analysis (source-analyze source
#:lines lines
#:analyzers (refactoring-suite-analyzers effective-suite)))
#:analyzers (refactoring-suite-analyzers effective-suite)
#:timeout-ms timeout-ms))
(refactor-visited-forms
#:analysis analysis #:suite effective-suite #:comments comments #:lines lines)))

Expand All@@ -229,7 +232,9 @@
[else result-set]))


(define/guard (reysntax-analyze-for-properties-only source #:suite [suite default-recommendations])
(define/guard (reysntax-analyze-for-properties-only source
#:suite [suite default-recommendations]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define full-source (source->string source))
(guard (string-prefix? full-source "#lang racket") #:else
Expand All@@ -251,7 +256,8 @@
[exn:fail:filesystem:missing-module? skip]
[exn:fail:contract:variable? skip])
(define analysis (source-analyze source
#:analyzers (refactoring-suite-analyzers suite)))
#:analyzers (refactoring-suite-analyzers suite)
#:timeout-ms timeout-ms))
(source-code-analysis-added-syntax-properties analysis)))


Expand All@@ -260,7 +266,8 @@
#:max-fixes [max-fixes +inf.0]
#:max-passes [max-passes 10]
#:max-modified-sources [max-modified-sources +inf.0]
#:max-modified-lines [max-modified-lines +inf.0])
#:max-modified-lines [max-modified-lines +inf.0]
#:timeout-ms [timeout-ms 10000])
(log-resyntax-info "--- analyzing code ---")
(for/fold ([pass-result-lists '()]
[sources sources]
Expand All@@ -274,7 +281,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms))
(define pass-fix-count (count-total-results pass-results))
(define new-max-fixes (- max-fixes pass-fix-count))]
#:break (hash-empty? pass-results)
Expand All@@ -298,7 +306,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines)
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms)
(transduce (in-hash-entries sources) ; entries with source keys and line range set values

;; The following steps perform a kind of layered shuffle: the files to refactor are
Expand DownExpand Up@@ -326,7 +335,7 @@
(append-mapping
(λ (e)
(match-define (entry source lines) e)
(define result-set (resyntax-analyze source #:suite suite #:lines lines))
(define result-set (resyntax-analyze source #:suite suite #:lines lines #:timeout-ms timeout-ms))
(refactoring-result-set-results result-set)))
(limiting max-modified-lines
#:by (λ (result)
Expand DownExpand Up@@ -524,6 +533,7 @@
;; Test with multipass analyze
(define analysis
(resyntax-analyze-all (hash test-source (range-set (unbounded-range #:comparator natural<=>)))
#:suite breaking-suite))
#:suite breaking-suite
#:timeout-ms 10000))
(check-equal? (resyntax-analysis-total-fixes analysis) 0
"Breaking suggestions should be filtered from resyntax-analyze-all")))
43 changes: 19 additions & 24 deletions private/analysis.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@

(provide
(contract-out
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?))
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?) #:timeout-ms exact-nonnegative-integer?)
(#:lines range-set?)
source-code-analysis?)]
[source-code-analysis? (-> any/c boolean?)]
Expand DownExpand Up@@ -68,15 +68,9 @@
(syntax-ref stx path)))


;; Timeout for analyzers in seconds
(define analyzer-timeout-seconds 10)

;; Milliseconds per second (for time conversions)
(define milliseconds-per-second 1000)

;; Run an analyzer with a timeout. Returns the result or an empty syntax property bundle
;; if timeout occurred or an error was raised.
(define (run-analyzer-with-timeout analyzer expanded source-name)
(define (run-analyzer-with-timeout analyzer expanded source-name timeout-ms)
(define result-box (box #false))
(define error-box (box #false))
(define start-time (current-inexact-milliseconds))
Expand All@@ -87,8 +81,7 @@
(with-handlers ([exn:fail? (λ (e) (set-box! error-box e))])
(set-box! result-box (expansion-analyze analyzer expanded))))))

(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds)
(* analyzer-timeout-seconds milliseconds-per-second))))
(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds) timeout-ms)))

;; Wait for either completion or timeout
(define final-result
Expand All@@ -100,9 +93,9 @@
[(eq? final-result 'timeout)
(kill-thread analyzer-thread)
(log-resyntax-warning
"analyzer ~a timed out after ~a seconds while analyzing ~a"
"analyzer ~a timed out after ~a ms while analyzing ~a"
(object-name analyzer)
analyzer-timeout-seconds
timeout-ms
source-name)
(syntax-property-bundle)]
[else
Expand All@@ -125,7 +118,8 @@

(define (source-analyze code
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:analyzers analyzers)
#:analyzers analyzers
#:timeout-ms timeout-ms)
(define ns (make-base-namespace))
(parameterize ([current-directory (or (source-directory code) (current-directory))]
[current-namespace ns])
Expand DownExpand Up@@ -245,7 +239,7 @@
(transduce analyzers
(append-mapping
(λ (analyzer)
(define result (run-analyzer-with-timeout analyzer expanded program-source-name))
(define result (run-analyzer-with-timeout analyzer expanded program-source-name timeout-ms))
(syntax-property-bundle-entries result)))
(filtering
(λ (prop-entry)
Expand DownExpand Up@@ -312,20 +306,21 @@
(define test-source (string-source "#lang racket/base (define x 1)"))

;; Test with empty analyzers list
(define analysis-empty (source-analyze test-source #:analyzers '()))
(define analysis-empty (source-analyze test-source #:analyzers '() #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-empty))

;; Test with single analyzer
(define analysis-single
(source-analyze test-source #:analyzers (list identifier-usage-analyzer)))
(source-analyze test-source #:analyzers (list identifier-usage-analyzer) #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-single))

;; Test with default analyzers (should match default behavior)
(define analysis-default
(source-analyze test-source
#:analyzers (list identifier-usage-analyzer
ignored-result-values-analyzer
variable-mutability-analyzer)))
variable-mutability-analyzer)
#:timeout-ms 10000))
(check-true (source-code-analysis? analysis-default)))

(test-case "source-analyze filters out properties with invalid paths"
Expand All@@ -345,7 +340,7 @@
(syntax-property-entry (syntax-path (list 0 999)) 'another-invalid-prop #true)))))

;; Run analysis with the bad analyzer - should not crash
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed successfully
(check-true (source-code-analysis? analysis))
Expand All@@ -372,13 +367,13 @@
(make-expansion-analyzer
#:name 'slow-analyzer
(λ (expanded)
;; Sleep for 11 seconds - slightly longer than the 10 second timeout
(sleep 11)
;; Sleep for 200ms - longer than a 100ms timeout
(sleep 0.2)
(syntax-property-bundle
(syntax-property-entry empty-syntax-path 'slow-prop #true)))))

;; Run analysis with the slow analyzer - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer)))
;; Run analysis with the slow analyzer and a short timeout - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer) #:timeout-ms 100))

;; Check that the analysis completed (even though the analyzer timed out)
(check-true (source-code-analysis? analysis))
Expand All@@ -403,7 +398,7 @@
(syntax-property-entry empty-syntax-path 'fast-prop #true)))))

;; Run analysis with the fast analyzer - should complete successfully
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed
(check-true (source-code-analysis? analysis))
Expand All@@ -427,7 +422,7 @@
(error "intentional test error"))))

;; Run analysis with the failing analyzer - should skip it and not crash
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed (even though the analyzer failed)
(check-true (source-code-analysis? analysis))))
16 changes: 15 additions & 1 deletion test.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,7 +147,21 @@

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-line-mask)
#:with (value ...) (list #'line-set)))
#:with (value ...) (list #'line-set))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-analyzer-timeout-millis)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...)))
(#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-line-mask #'current-analyzer-timeout-millis)
#:with (value ...) (list #'line-set #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number)
(#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-analyzer-timeout-millis #'current-line-mask)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value) #'line-set)))

(define-splicing-syntax-class code-block-test-args
#:attributes ([check 1])
Expand Down
18 changes: 18 additions & 0 deletions test/analyzer-timeout-test.rkt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
#lang resyntax/test


header:
------------------------------
#lang racket/base
------------------------------


test: "timeout parameter can be customized in tests"
@analyzer-timeout-millis 5000
- (or 1 (or 2 3))
- (or 1 2 3)


no-change-test: "timeout parameter works with no-change-test"
@analyzer-timeout-millis 5000
- (define x 42)
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 23 additions & 6 deletions cli.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -37,7 +37,7 @@

(define-enum-type resyntax-output-format (plain-text github-pull-request-review git-commit-message json))
(define-enum-type resyntax-fix-method (modify-files create-multiple-git-commits))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination))
(define-record-type resyntax-analyze-options (targets suite output-format output-destination analyzer-timeout-ms))


(define-record-type resyntax-fix-options
Expand All@@ -48,7 +48,8 @@
max-fixes
max-modified-files
max-modified-lines
max-pass-count))
max-pass-count
analyzer-timeout-ms))


(define all-lines (range-set (unbounded-range #:comparator natural<=>)))
Expand All@@ -60,6 +61,7 @@
(define selected-rule #false)
(define output-format plain-text)
(define output-destination 'console)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax analyze"
Expand DownExpand Up@@ -105,6 +107,11 @@ changed relative to baseref are analyzed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--output-to-file"
outputpath
"Store results in a file instead of printing them to the console."
Expand All@@ -128,7 +135,8 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
#:targets (build-vector targets)
#:suite suite
#:output-format output-format
#:output-destination output-destination))
#:output-destination output-destination
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-fix-parse-command-line)
Expand All@@ -143,6 +151,7 @@ determined by the GITHUB_REPOSITORY and GITHUB_REF environment variables."
(define max-pass-count 10)
(define max-modified-files +inf.0)
(define max-modified-lines +inf.0)
(define analyzer-timeout-ms 10000)

(command-line
#:program "resyntax fix"
Expand DownExpand Up@@ -197,6 +206,11 @@ changed relative to baseref are analyzed and fixed."
(define rule-sym (string->symbol rule-name))
(set! selected-rule rule-sym))

("--analyzer-timeout"
timeout-ms
"The timeout in milliseconds for expansion analyzers. Defaults to 10000 (10 seconds)."
(set! analyzer-timeout-ms (string->number timeout-ms)))

("--max-pass-count"
passcount
"The maximum number of times Resyntax will fix each file. By default, Resyntax runs at most 10 \
Expand DownExpand Up@@ -235,7 +249,8 @@ are needed when applying a fix unlocks further fixes."
#:max-fixes max-fixes
#:max-modified-files max-modified-files
#:max-modified-lines max-modified-lines
#:max-pass-count max-pass-count))
#:max-pass-count max-pass-count
#:analyzer-timeout-ms analyzer-timeout-ms))


(define (resyntax-run)
Expand DownExpand Up@@ -273,7 +288,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
(define analysis
(resyntax-analyze-all sources
#:suite (resyntax-analyze-options-suite options)
#:max-passes 1))
#:max-passes 1
#:timeout-ms (resyntax-analyze-options-analyzer-timeout-ms options)))
(define results
(transduce (resyntax-analysis-all-results analysis)
(append-mapping in-hash-values)
Expand DownExpand Up@@ -322,7 +338,8 @@ For help on these, use 'analyze --help' or 'fix --help'."
#:max-fixes (resyntax-fix-options-max-fixes options)
#:max-passes (resyntax-fix-options-max-pass-count options)
#:max-modified-sources max-modified-files
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms (resyntax-fix-options-analyzer-timeout-ms options)))
(match fix-method
[(== modify-files)
(resyntax-analysis-write-file-changes! analysis)]
Expand Down
34 changes: 22 additions & 12 deletions main.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,17 +17,18 @@
[resyntax-analysis-write-file-changes! (-> resyntax-analysis? void?)]
[resyntax-analysis-commit-fixes! (-> resyntax-analysis? void?)]
[resyntax-analyze
(->* (source?) (#:suite refactoring-suite? #:lines range-set?) refactoring-result-set?)]
(->* (source?) (#:suite refactoring-suite? #:lines range-set? #:timeout-ms exact-nonnegative-integer?) refactoring-result-set?)]
[resyntax-analyze-all
(->* ((hash/c source? range-set? #:flat? #true))
(#:suite refactoring-suite?
#:max-fixes (or/c exact-nonnegative-integer? +inf.0)
#:max-passes exact-nonnegative-integer?
#:max-modified-sources (or/c exact-nonnegative-integer? +inf.0)
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0))
#:max-modified-lines (or/c exact-nonnegative-integer? +inf.0)
#:timeout-ms exact-nonnegative-integer?)
resyntax-analysis?)]
[reysntax-analyze-for-properties-only
(->* (source?) (#:suite refactoring-suite?) syntax-property-bundle?)]
(->* (source?) (#:suite refactoring-suite? #:timeout-ms exact-nonnegative-integer?) syntax-property-bundle?)]
[refactor! (-> (sequence/c refactoring-result?) void?)]))


Expand DownExpand Up@@ -167,7 +168,8 @@

(define/guard (resyntax-analyze source
#:suite [suite default-recommendations]
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))])
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define source-lang (source-read-language source))
(guard source-lang #:else
Expand DownExpand Up@@ -210,7 +212,8 @@
(with-handlers ([exn:fail? skip])
(define analysis (source-analyze source
#:lines lines
#:analyzers (refactoring-suite-analyzers effective-suite)))
#:analyzers (refactoring-suite-analyzers effective-suite)
#:timeout-ms timeout-ms))
(refactor-visited-forms
#:analysis analysis #:suite effective-suite #:comments comments #:lines lines)))

Expand All@@ -229,7 +232,9 @@
[else result-set]))


(define/guard (reysntax-analyze-for-properties-only source #:suite [suite default-recommendations])
(define/guard (reysntax-analyze-for-properties-only source
#:suite [suite default-recommendations]
#:timeout-ms [timeout-ms 10000])
(define comments (with-input-from-source source read-comment-locations))
(define full-source (source->string source))
(guard (string-prefix? full-source "#lang racket") #:else
Expand All@@ -251,7 +256,8 @@
[exn:fail:filesystem:missing-module? skip]
[exn:fail:contract:variable? skip])
(define analysis (source-analyze source
#:analyzers (refactoring-suite-analyzers suite)))
#:analyzers (refactoring-suite-analyzers suite)
#:timeout-ms timeout-ms))
(source-code-analysis-added-syntax-properties analysis)))


Expand All@@ -260,7 +266,8 @@
#:max-fixes [max-fixes +inf.0]
#:max-passes [max-passes 10]
#:max-modified-sources [max-modified-sources +inf.0]
#:max-modified-lines [max-modified-lines +inf.0])
#:max-modified-lines [max-modified-lines +inf.0]
#:timeout-ms [timeout-ms 10000])
(log-resyntax-info "--- analyzing code ---")
(for/fold ([pass-result-lists '()]
[sources sources]
Expand All@@ -274,7 +281,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines))
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms))
(define pass-fix-count (count-total-results pass-results))
(define new-max-fixes (- max-fixes pass-fix-count))]
#:break (hash-empty? pass-results)
Expand All@@ -298,7 +306,8 @@
#:suite suite
#:max-fixes max-fixes
#:max-modified-sources max-modified-sources
#:max-modified-lines max-modified-lines)
#:max-modified-lines max-modified-lines
#:timeout-ms timeout-ms)
(transduce (in-hash-entries sources) ; entries with source keys and line range set values

;; The following steps perform a kind of layered shuffle: the files to refactor are
Expand DownExpand Up@@ -326,7 +335,7 @@
(append-mapping
(λ (e)
(match-define (entry source lines) e)
(define result-set (resyntax-analyze source #:suite suite #:lines lines))
(define result-set (resyntax-analyze source #:suite suite #:lines lines #:timeout-ms timeout-ms))
(refactoring-result-set-results result-set)))
(limiting max-modified-lines
#:by (λ (result)
Expand DownExpand Up@@ -524,6 +533,7 @@
;; Test with multipass analyze
(define analysis
(resyntax-analyze-all (hash test-source (range-set (unbounded-range #:comparator natural<=>)))
#:suite breaking-suite))
#:suite breaking-suite
#:timeout-ms 10000))
(check-equal? (resyntax-analysis-total-fixes analysis) 0
"Breaking suggestions should be filtered from resyntax-analyze-all")))
43 changes: 19 additions & 24 deletions private/analysis.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,7 +6,7 @@

(provide
(contract-out
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?))
[source-analyze (->* (source? #:analyzers (sequence/c expansion-analyzer?) #:timeout-ms exact-nonnegative-integer?)
(#:lines range-set?)
source-code-analysis?)]
[source-code-analysis? (-> any/c boolean?)]
Expand DownExpand Up@@ -68,15 +68,9 @@
(syntax-ref stx path)))


;; Timeout for analyzers in seconds
(define analyzer-timeout-seconds 10)

;; Milliseconds per second (for time conversions)
(define milliseconds-per-second 1000)

;; Run an analyzer with a timeout. Returns the result or an empty syntax property bundle
;; if timeout occurred or an error was raised.
(define (run-analyzer-with-timeout analyzer expanded source-name)
(define (run-analyzer-with-timeout analyzer expanded source-name timeout-ms)
(define result-box (box #false))
(define error-box (box #false))
(define start-time (current-inexact-milliseconds))
Expand All@@ -87,8 +81,7 @@
(with-handlers ([exn:fail? (λ (e) (set-box! error-box e))])
(set-box! result-box (expansion-analyze analyzer expanded))))))

(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds)
(* analyzer-timeout-seconds milliseconds-per-second))))
(define timeout-evt (alarm-evt (+ (current-inexact-milliseconds) timeout-ms)))

;; Wait for either completion or timeout
(define final-result
Expand All@@ -100,9 +93,9 @@
[(eq? final-result 'timeout)
(kill-thread analyzer-thread)
(log-resyntax-warning
"analyzer ~a timed out after ~a seconds while analyzing ~a"
"analyzer ~a timed out after ~a ms while analyzing ~a"
(object-name analyzer)
analyzer-timeout-seconds
timeout-ms
source-name)
(syntax-property-bundle)]
[else
Expand All@@ -125,7 +118,8 @@

(define (source-analyze code
#:lines [lines (range-set (unbounded-range #:comparator natural<=>))]
#:analyzers analyzers)
#:analyzers analyzers
#:timeout-ms timeout-ms)
(define ns (make-base-namespace))
(parameterize ([current-directory (or (source-directory code) (current-directory))]
[current-namespace ns])
Expand DownExpand Up@@ -245,7 +239,7 @@
(transduce analyzers
(append-mapping
(λ (analyzer)
(define result (run-analyzer-with-timeout analyzer expanded program-source-name))
(define result (run-analyzer-with-timeout analyzer expanded program-source-name timeout-ms))
(syntax-property-bundle-entries result)))
(filtering
(λ (prop-entry)
Expand DownExpand Up@@ -312,20 +306,21 @@
(define test-source (string-source "#lang racket/base (define x 1)"))

;; Test with empty analyzers list
(define analysis-empty (source-analyze test-source #:analyzers '()))
(define analysis-empty (source-analyze test-source #:analyzers '() #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-empty))

;; Test with single analyzer
(define analysis-single
(source-analyze test-source #:analyzers (list identifier-usage-analyzer)))
(source-analyze test-source #:analyzers (list identifier-usage-analyzer) #:timeout-ms 10000))
(check-true (source-code-analysis? analysis-single))

;; Test with default analyzers (should match default behavior)
(define analysis-default
(source-analyze test-source
#:analyzers (list identifier-usage-analyzer
ignored-result-values-analyzer
variable-mutability-analyzer)))
variable-mutability-analyzer)
#:timeout-ms 10000))
(check-true (source-code-analysis? analysis-default)))

(test-case "source-analyze filters out properties with invalid paths"
Expand All@@ -345,7 +340,7 @@
(syntax-property-entry (syntax-path (list 0 999)) 'another-invalid-prop #true)))))

;; Run analysis with the bad analyzer - should not crash
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list bad-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed successfully
(check-true (source-code-analysis? analysis))
Expand All@@ -372,13 +367,13 @@
(make-expansion-analyzer
#:name 'slow-analyzer
(λ (expanded)
;; Sleep for 11 seconds - slightly longer than the 10 second timeout
(sleep 11)
;; Sleep for 200ms - longer than a 100ms timeout
(sleep 0.2)
(syntax-property-bundle
(syntax-property-entry empty-syntax-path 'slow-prop #true)))))

;; Run analysis with the slow analyzer - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer)))
;; Run analysis with the slow analyzer and a short timeout - should timeout and not crash
(define analysis (source-analyze test-source #:analyzers (list slow-analyzer) #:timeout-ms 100))

;; Check that the analysis completed (even though the analyzer timed out)
(check-true (source-code-analysis? analysis))
Expand All@@ -403,7 +398,7 @@
(syntax-property-entry empty-syntax-path 'fast-prop #true)))))

;; Run analysis with the fast analyzer - should complete successfully
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list fast-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed
(check-true (source-code-analysis? analysis))
Expand All@@ -427,7 +422,7 @@
(error "intentional test error"))))

;; Run analysis with the failing analyzer - should skip it and not crash
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer)))
(define analysis (source-analyze test-source #:analyzers (list failing-analyzer) #:timeout-ms 10000))

;; Check that the analysis completed (even though the analyzer failed)
(check-true (source-code-analysis? analysis))))
16 changes: 15 additions & 1 deletion test.rkt
Original file line numberDiff line numberDiff line change
Expand Up@@ -147,7 +147,21 @@

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-line-mask)
#:with (value ...) (list #'line-set)))
#:with (value ...) (list #'line-set))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-analyzer-timeout-millis)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:lines (~and line-set (#:range-set _ ...)))
(#:option #:analyzer-timeout-millis timeout-value:number))
#:with (id ...) (list #'current-line-mask #'current-analyzer-timeout-millis)
#:with (value ...) (list #'line-set #`'#,(syntax-e #'timeout-value)))

(pattern (~seq (#:option #:analyzer-timeout-millis timeout-value:number)
(#:option #:lines (~and line-set (#:range-set _ ...))))
#:with (id ...) (list #'current-analyzer-timeout-millis #'current-line-mask)
#:with (value ...) (list #`'#,(syntax-e #'timeout-value) #'line-set)))

(define-splicing-syntax-class code-block-test-args
#:attributes ([check 1])
Expand Down
18 changes: 18 additions & 0 deletions test/analyzer-timeout-test.rkt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
#lang resyntax/test


header:
------------------------------
#lang racket/base
------------------------------


test: "timeout parameter can be customized in tests"
@analyzer-timeout-millis 5000
- (or 1 (or 2 3))
- (or 1 2 3)


no-change-test: "timeout parameter works with no-change-test"
@analyzer-timeout-millis 5000
- (define x 42)
Loading
Loading