@@ -1359,6 +1359,8 @@ func (c *linkerContext) scanImportsAndExports() {
13591359 }
13601360 }
13611361
1362+ c .validateComposesFromProperties (file , repr )
1363+
13621364 case * graph.JSRepr :
13631365 for importRecordIndex := range repr .AST .ImportRecords {
13641366 record := & repr .AST .ImportRecords [importRecordIndex ]
@@ -2003,6 +2005,86 @@ func (c *linkerContext) scanImportsAndExports() {
20032005 c .timer .End ("Step 6" )
20042006}
20052007
2008+ func (c * linkerContext ) validateComposesFromProperties (rootFile * graph.LinkerFile , rootRepr * graph.CSSRepr ) {
2009+ for _ , local := range rootRepr .AST .LocalSymbols {
2010+ type propertyInFile struct {
2011+ file * graph.LinkerFile
2012+ loc logger.Loc
2013+ }
2014+
2015+ visited := make (map [ast.Ref ]bool )
2016+ properties := make (map [string ]propertyInFile )
2017+ var visit func (* graph.LinkerFile , * graph.CSSRepr , ast.Ref )
2018+
2019+ visit = func (file * graph.LinkerFile , repr * graph.CSSRepr , ref ast.Ref ) {
2020+ if visited [ref ] {
2021+ return
2022+ }
2023+ visited [ref ] = true
2024+
2025+ composes , ok := repr .AST .Composes [ref ]
2026+ if ! ok {
2027+ return
2028+ }
2029+
2030+ for _ , name := range composes .ImportedNames {
2031+ if record := repr .AST .ImportRecords [name .ImportRecordIndex ]; record .SourceIndex .IsValid () {
2032+ otherFile := & c .graph .Files [record .SourceIndex .GetIndex ()]
2033+ if otherRepr , ok := otherFile .InputFile .Repr .(* graph.CSSRepr ); ok {
2034+ if otherName , ok := otherRepr .AST .LocalScope [name .Alias ]; ok {
2035+ visit (otherFile , otherRepr , otherName .Ref )
2036+ }
2037+ }
2038+ }
2039+ }
2040+
2041+ for _ , name := range composes .Names {
2042+ visit (file , repr , name .Ref )
2043+ }
2044+
2045+ // Warn about cross-file composition with the same CSS properties
2046+ for keyText , keyLoc := range composes .Properties {
2047+ property , ok := properties [keyText ]
2048+ if ! ok {
2049+ properties [keyText ] = propertyInFile {file , keyLoc }
2050+ continue
2051+ }
2052+ if property .file == file || property .file == nil {
2053+ continue
2054+ }
2055+
2056+ localOriginalName := c .graph .Symbols .Get (local .Ref ).OriginalName
2057+ c .log .AddMsgID (logger .MsgID_CSS_UndefinedComposesFrom , logger.Msg {
2058+ Kind : logger .Warning ,
2059+ Data : rootFile .LineColumnTracker ().MsgData (
2060+ css_lexer .RangeOfIdentifier (rootFile .InputFile .Source , local .Loc ),
2061+ fmt .Sprintf ("The value of %q in the %q class is undefined" , keyText , localOriginalName ),
2062+ ),
2063+ Notes : []logger.MsgData {
2064+ property .file .LineColumnTracker ().MsgData (
2065+ css_lexer .RangeOfIdentifier (property .file .InputFile .Source , property .loc ),
2066+ fmt .Sprintf ("The first definition of %q is here:" , keyText ),
2067+ ),
2068+ file .LineColumnTracker ().MsgData (
2069+ css_lexer .RangeOfIdentifier (file .InputFile .Source , keyLoc ),
2070+ fmt .Sprintf ("The second definition of %q is here:" , keyText ),
2071+ ),
2072+ {Text : fmt .Sprintf ("The specification of \" composes\" does not define an order when class declarations from separate files are composed together. " +
2073+ "The value of the %q property for %q may change unpredictably as the code is edited. " +
2074+ "Make sure that all definitions of %q for %q are in a single file." , keyText , localOriginalName , keyText , localOriginalName )},
2075+ },
2076+ })
2077+
2078+ // Don't warn more than once
2079+ property .file = nil
2080+ properties [keyText ] = property
2081+ }
2082+ }
2083+
2084+ visit (rootFile , rootRepr , local .Ref )
2085+ }
2086+ }
2087+
20062088func (c * linkerContext ) generateCodeForLazyExport (sourceIndex uint32 ) {
20072089 file := & c .graph .Files [sourceIndex ]
20082090 repr := file .InputFile .Repr .(* graph.JSRepr )
0 commit comments