Skip to content

Commit 0d67b86

Browse files
committed
Extract ExtractedDirectives out from ScalaPreprocessor
1 parent 76ad193 commit 0d67b86

File tree

4 files changed

+127
-109
lines changed

4 files changed

+127
-109
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package scala.build.preprocessing
2+
3+
import com.virtuslab.using_directives.config.Settings
4+
import com.virtuslab.using_directives.custom.model.{
5+
UsingDirectiveKind,
6+
UsingDirectiveSyntax,
7+
UsingDirectives
8+
}
9+
import com.virtuslab.using_directives.custom.utils.ast.{UsingDef, UsingDefs}
10+
import com.virtuslab.using_directives.{Context, UsingDirectivesProcessor}
11+
12+
import scala.build.errors._
13+
import scala.build.preprocessing.directives.StrictDirective
14+
import scala.build.{Logger, Position}
15+
import scala.collection.mutable
16+
import scala.jdk.CollectionConverters._
17+
18+
case class ExtractedDirectives(
19+
offset: Int,
20+
directives: Seq[StrictDirective],
21+
kind: UsingDirectiveKind
22+
)
23+
24+
object ExtractedDirectives {
25+
26+
val changeToSpecialCommentMsg =
27+
"Using directive using plain comments are deprecated. Please use a special comment syntax: '//> ...' or '/*> ... */'"
28+
29+
def from(
30+
contentChars: Array[Char],
31+
path: Either[String, os.Path],
32+
logger: Logger
33+
): Either[BuildException, ExtractedDirectives] = {
34+
val errors = new mutable.ListBuffer[Diagnostic]
35+
val reporter = CustomDirectivesReporter.create(path) { diag =>
36+
if (diag.severity == Severity.Warning)
37+
logger.log(Seq(diag))
38+
else
39+
errors += diag
40+
}
41+
val processor = {
42+
val settings = new Settings
43+
settings.setAllowStartWithoutAt(true)
44+
settings.setAllowRequire(false)
45+
val context = new Context(reporter, settings)
46+
new UsingDirectivesProcessor(context)
47+
}
48+
val all = processor.extract(contentChars, true, true).asScala
49+
if (errors.isEmpty) {
50+
51+
def byKind(kind: UsingDirectiveKind) = all.find(_.getKind == kind).get
52+
53+
def getDirectives(directives: UsingDirectives) =
54+
directives.getAst() match {
55+
case ud: UsingDefs =>
56+
ud.getUsingDefs().asScala
57+
case _ =>
58+
Nil
59+
}
60+
61+
val codeDirectives = byKind(UsingDirectiveKind.Code)
62+
val specialCommentDirectives = byKind(UsingDirectiveKind.SpecialComment)
63+
val plainCommentDirectives = byKind(UsingDirectiveKind.PlainComment)
64+
65+
def reportWarning(msg: String, values: Seq[UsingDef], before: Boolean = true): Unit =
66+
values.foreach { v =>
67+
val astPos = v.getPosition()
68+
val (start, end) =
69+
if (before) (0, astPos.getColumn())
70+
else (astPos.getColumn(), astPos.getColumn() + v.getSyntax.getKeyword.size)
71+
val position = Position.File(path, (astPos.getLine(), start), (astPos.getLine(), end))
72+
logger.diagnostic(msg, positions = Seq(position))
73+
}
74+
75+
val usedDirectives =
76+
if (!codeDirectives.getFlattenedMap().isEmpty()) {
77+
val msg =
78+
"This using directive is ignored. File contains directives outside comments and those have higher precedence."
79+
reportWarning(
80+
msg,
81+
getDirectives(plainCommentDirectives) ++ getDirectives(specialCommentDirectives)
82+
)
83+
codeDirectives
84+
}
85+
else if (!specialCommentDirectives.getFlattenedMap().isEmpty()) {
86+
val msg =
87+
s"This using directive is ignored. $changeToSpecialCommentMsg"
88+
reportWarning(msg, getDirectives(plainCommentDirectives))
89+
specialCommentDirectives
90+
}
91+
else {
92+
reportWarning(changeToSpecialCommentMsg, getDirectives(plainCommentDirectives))
93+
plainCommentDirectives
94+
}
95+
96+
// All using directives should use just `using` keyword, no @using or require
97+
reportWarning(
98+
"Deprecated using directive syntax, please use keyword `using`.",
99+
getDirectives(usedDirectives).filter(_.getSyntax() != UsingDirectiveSyntax.Using),
100+
before = false
101+
)
102+
103+
val flattened = usedDirectives.getFlattenedMap.asScala.toSeq
104+
val strictDirectives =
105+
flattened.map {
106+
case (k, l) =>
107+
StrictDirective(k.getPath.asScala.mkString("."), l.asScala.toSeq)
108+
}
109+
110+
val offset =
111+
if (usedDirectives.getKind() != UsingDirectiveKind.Code) 0
112+
else usedDirectives.getCodeOffset()
113+
Right(ExtractedDirectives(offset, strictDirectives, usedDirectives.getKind()))
114+
}
115+
else {
116+
val errors0 = errors.map(diag => new MalformedDirectiveError(diag.message, diag.positions))
117+
Left(CompositeBuildException(errors0.toSeq))
118+
}
119+
}
120+
}

modules/build/src/main/scala/scala/build/preprocessing/JavaPreprocessor.scala

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import java.nio.charset.StandardCharsets
66
import scala.build.EitherCps.{either, value}
77
import scala.build.errors.{BuildException, DirectiveErrors}
88
import scala.build.options.BuildRequirements
9+
import scala.build.preprocessing.ExtractedDirectives.from
910
import scala.build.preprocessing.ScalaPreprocessor._
1011
import scala.build.{Inputs, Logger}
1112

@@ -19,7 +20,7 @@ case object JavaPreprocessor extends Preprocessor {
1920
val content = value(PreprocessingUtil.maybeRead(j.path))
2021
val scopePath = ScopePath.fromPath(j.path)
2122
val ExtractedDirectives(_, directives0, kind) =
22-
value(extractUsingDirectives(content.toCharArray, Right(j.path), logger))
23+
value(from(content.toCharArray, Right(j.path), logger))
2324
val _ = value(assertKindIsNotCode(kind))
2425
val updatedOptions = value(DirectivesProcessor.process(
2526
directives0,

modules/build/src/main/scala/scala/build/preprocessing/ScalaPreprocessor.scala

Lines changed: 3 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,15 @@
11
package scala.build.preprocessing
22

3-
import com.virtuslab.using_directives.config.Settings
4-
import com.virtuslab.using_directives.custom.model.{
5-
UsingDirectiveKind,
6-
UsingDirectiveSyntax,
7-
UsingDirectives
8-
}
9-
import com.virtuslab.using_directives.custom.utils.ast.{UsingDef, UsingDefs}
10-
import com.virtuslab.using_directives.{Context, UsingDirectivesProcessor}
113
import dependency.AnyDependency
124
import dependency.parser.DependencyParser
135

146
import java.nio.charset.StandardCharsets
15-
167
import scala.build.EitherCps.{either, value}
178
import scala.build.Ops._
189
import scala.build.errors._
1910
import scala.build.internal.{AmmUtil, Util}
2011
import scala.build.options.{BuildOptions, BuildRequirements, ClassPathOptions, ShadowingSeq}
12+
import scala.build.preprocessing.ExtractedDirectives.from
2113
import scala.build.preprocessing.directives._
2214
import scala.build.{Inputs, Logger, Position, Positioned}
2315
import scala.collection.mutable
@@ -189,6 +181,7 @@ case object ScalaPreprocessor extends Preprocessor {
189181
): Either[BuildException, Option[SpecialImportsProcessingOutput]] = either {
190182

191183
import fastparse._
184+
192185
import scala.build.internal.ScalaParse._
193186

194187
val res = parse(content, Header(_))
@@ -275,7 +268,7 @@ case object ScalaPreprocessor extends Preprocessor {
275268
logger: Logger
276269
): Either[BuildException, StrictDirectivesProcessingOutput] = either {
277270
val contentChars = content.toCharArray
278-
val ExtractedDirectives(codeOffset, directives0, _) = value(extractUsingDirectives(contentChars, path, logger))
271+
val ExtractedDirectives(codeOffset, directives0, _) = value(ExtractedDirectives.from(contentChars, path, logger))
279272

280273
val updatedOptions = value {
281274
DirectivesProcessor.process(
@@ -345,103 +338,9 @@ case object ScalaPreprocessor extends Preprocessor {
345338
new UnusedDirectiveError(directive.key, values.map(_._1.value), values.flatMap(_._1.positions))
346339
}
347340

348-
case class ExtractedDirectives(offset: Int, directives: Seq[StrictDirective], kind: UsingDirectiveKind)
349-
350341
val changeToSpecialCommentMsg =
351342
"Using directive using plain comments are deprecated. Please use a special comment syntax: '//> ...' or '/*> ... */'"
352343

353-
def extractUsingDirectives(
354-
contentChars: Array[Char],
355-
path: Either[String, os.Path],
356-
logger: Logger
357-
): Either[BuildException, ExtractedDirectives] = {
358-
val errors = new mutable.ListBuffer[Diagnostic]
359-
val reporter = CustomDirectivesReporter.create(path) { diag =>
360-
if (diag.severity == Severity.Warning)
361-
logger.log(Seq(diag))
362-
else
363-
errors += diag
364-
}
365-
val processor = {
366-
val settings = new Settings
367-
settings.setAllowStartWithoutAt(true)
368-
settings.setAllowRequire(false)
369-
val context = new Context(reporter, settings)
370-
new UsingDirectivesProcessor(context)
371-
}
372-
val all = processor.extract(contentChars, true, true).asScala
373-
if (errors.isEmpty) {
374-
375-
def byKind(kind: UsingDirectiveKind) = all.find(_.getKind == kind).get
376-
377-
def getDirectives(directives: UsingDirectives) =
378-
directives.getAst() match {
379-
case ud: UsingDefs =>
380-
ud.getUsingDefs().asScala.toSeq
381-
case _ =>
382-
Nil
383-
}
384-
385-
val codeDirectives = byKind(UsingDirectiveKind.Code)
386-
val specialCommentDirectives = byKind(UsingDirectiveKind.SpecialComment)
387-
val plainCommentDirectives = byKind(UsingDirectiveKind.PlainComment)
388-
389-
def reportWarning(msg: String, values: Seq[UsingDef], before: Boolean = true): Unit =
390-
values.foreach { v =>
391-
val astPos = v.getPosition()
392-
val (start, end) =
393-
if (before) (0, astPos.getColumn())
394-
else (astPos.getColumn(), astPos.getColumn() + v.getSyntax.getKeyword.size)
395-
val position = Position.File(path, (astPos.getLine(), start), (astPos.getLine(), end))
396-
logger.diagnostic(msg, positions = Seq(position))
397-
}
398-
399-
val usedDirectives =
400-
if (!codeDirectives.getFlattenedMap().isEmpty()) {
401-
val msg =
402-
"This using directive is ignored. File contains directives outside comments and those have higher precedence."
403-
reportWarning(
404-
msg,
405-
getDirectives(plainCommentDirectives) ++ getDirectives(specialCommentDirectives)
406-
)
407-
codeDirectives
408-
}
409-
else if (!specialCommentDirectives.getFlattenedMap().isEmpty()) {
410-
val msg =
411-
s"This using directive is ignored. $changeToSpecialCommentMsg"
412-
reportWarning(msg, getDirectives(plainCommentDirectives))
413-
specialCommentDirectives
414-
}
415-
else {
416-
reportWarning(changeToSpecialCommentMsg, getDirectives(plainCommentDirectives))
417-
plainCommentDirectives
418-
}
419-
420-
// All using directives should use just `using` keyword, no @using or require
421-
reportWarning(
422-
"Deprecated using directive syntax, please use keyword `using`.",
423-
getDirectives(usedDirectives).filter(_.getSyntax() != UsingDirectiveSyntax.Using),
424-
before = false
425-
)
426-
427-
val flattened = usedDirectives.getFlattenedMap.asScala.toSeq
428-
val strictDirectives =
429-
flattened.map {
430-
case (k, l) =>
431-
StrictDirective(k.getPath.asScala.mkString("."), l.asScala.toSeq)
432-
}
433-
434-
val offset =
435-
if (usedDirectives.getKind() != UsingDirectiveKind.Code) 0
436-
else usedDirectives.getCodeOffset()
437-
Right(ExtractedDirectives(offset, strictDirectives, usedDirectives.getKind()))
438-
}
439-
else {
440-
val errors0 = errors.map(diag => new MalformedDirectiveError(diag.message, diag.positions))
441-
Left(CompositeBuildException(errors0.toSeq))
442-
}
443-
}
444-
445344
private def parseDependency(str: String, pos: Position): Either[BuildException, AnyDependency] =
446345
DependencyParser.parse(str) match {
447346
case Left(msg) => Left(new DependencyFormatError(str, msg, positionOpt = Some(pos)))

modules/build/src/test/scala/scala/build/tests/ScalaPreprocessorTests.scala

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@ package tests
33

44
import com.eed3si9n.expecty.Expecty.{assert => expect}
55

6-
import scala.build.Logger
76
import scala.build.errors.Diagnostic
8-
import scala.build.preprocessing.ScalaPreprocessor
7+
import scala.build.preprocessing.ExtractedDirectives
98

109
class ScalaPreprocessorTests extends munit.FunSuite {
1110

@@ -40,8 +39,7 @@ class ScalaPreprocessorTests extends munit.FunSuite {
4039
private def testWarnings(lines: String*)(expectedWarnings: Check*): Unit = {
4140
val persistentLogger = new PersistentDiagnosticLogger(Logger.nop)
4241
val code = lines.mkString("\n").toCharArray()
43-
val res =
44-
ScalaPreprocessor.extractUsingDirectives(code, Right(path), persistentLogger)
42+
val res = ExtractedDirectives.from(code, Right(path), persistentLogger)
4543
expect(res.isRight)
4644

4745
val diags = persistentLogger.diagnostics

0 commit comments

Comments
 (0)