diff --git a/glass-easel-miniprogram-webpack-plugin/index.ts b/glass-easel-miniprogram-webpack-plugin/index.ts index 00ec8ea..538477c 100644 --- a/glass-easel-miniprogram-webpack-plugin/index.ts +++ b/glass-easel-miniprogram-webpack-plugin/index.ts @@ -3,6 +3,7 @@ import { promises as fs } from 'node:fs' import * as path from 'node:path' import { NormalModule, type Compiler, type WebpackPluginInstance } from 'webpack' +import chalk from 'chalk' import { TmplGroup } from 'glass-easel-template-compiler' import { escapeJsString } from './helpers' @@ -11,6 +12,18 @@ type VirtualModulePluginType = { writeModule: (p: string, c: string) => void } +type Warning = { + isError: boolean + level: number + code: number + message: string + path: string + startLine: number + startColumn: number + endLine: number + endColumn: number +} + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const chokidar = require('chokidar') // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment @@ -423,7 +436,19 @@ export class GlassEaselMiniprogramWebpackPlugin implements WebpackPluginInstance x.options = { addTemplate(content: string) { wxmlContentMap[compPath] = content - depsTmplGroup.addTmpl(compPath, content) + const warnings = depsTmplGroup.addTmpl(compPath, content) as Warning[] + if (warnings && warnings.length > 0) { + warnings.forEach((warning) => { + const msgKindColored = warning.isError + ? chalk.red('ERROR') + : chalk.yellow('WARN') + const msg = `[glass-easel-template-compiler] ${msgKindColored} ${warning.path}:${warning.startLine}:${warning.startColumn} (#${warning.code}): ${warning.message}` + // eslint-disable-next-line no-console + if (warning.isError) console.error(msg) + // eslint-disable-next-line no-console + else console.warn(msg) + }) + } const deps = depsTmplGroup .getDirectDependencies(compPath) .concat(depsTmplGroup.getScriptDependencies(compPath)) diff --git a/glass-easel-miniprogram-webpack-plugin/package.json b/glass-easel-miniprogram-webpack-plugin/package.json index ed7f647..38988d5 100644 --- a/glass-easel-miniprogram-webpack-plugin/package.json +++ b/glass-easel-miniprogram-webpack-plugin/package.json @@ -26,6 +26,7 @@ "webpack": "^5.85.0" }, "dependencies": { + "chalk": "4", "chokidar": "^3.5.3", "glass-easel-stylesheet-compiler": "workspace:*", "glass-easel-template-compiler": "workspace:*", diff --git a/glass-easel-miniprogram-webpack-plugin/wxss_loader.js b/glass-easel-miniprogram-webpack-plugin/wxss_loader.js index d3ae4a5..7294482 100644 --- a/glass-easel-miniprogram-webpack-plugin/wxss_loader.js +++ b/glass-easel-miniprogram-webpack-plugin/wxss_loader.js @@ -1,5 +1,6 @@ /* eslint-disable */ +const chalk = require('chalk') const { SourceMapGenerator, SourceMapConsumer } = require('source-map') const { StyleSheetTransformer } = require('glass-easel-stylesheet-compiler') @@ -8,6 +9,17 @@ module.exports = function (src, prevMap, meta) { const { classPrefix, compPath, setLowPriorityStyles } = this.query const sst = new StyleSheetTransformer(this.resourcePath, src, classPrefix, 750, compPath) setLowPriorityStyles(sst.getLowPriorityContent(), sst.getLowPrioritySourceMap()) + const warnings = sst.extractWarnings() + if (warnings && warnings.length > 0) { + warnings.forEach((warning) => { + const msgKindColored = warning.isError + ? chalk.red('ERROR') + : chalk.yellow('WARN') + const msg = `[glass-easel-stylesheet-compiler] ${msgKindColored} ${warning.path}:${warning.startLine}:${warning.startColumn} (#${warning.code}): ${warning.message}` + if (warning.isError) console.error(msg) + else console.warn(msg) + }) + } const ss = sst.getContent() let map if (this.sourceMap) { diff --git a/glass-easel-stylesheet-compiler/src/lib.rs b/glass-easel-stylesheet-compiler/src/lib.rs index a8017e0..124c0a0 100644 --- a/glass-easel-stylesheet-compiler/src/lib.rs +++ b/glass-easel-stylesheet-compiler/src/lib.rs @@ -432,22 +432,28 @@ fn parse_qualified_rule(input: &mut StepParser, ss: &mut StyleSheetTransformer) let quoted_host_is = Token::QuotedString(host_is.clone().into()); let r = input.try_parse::<_, _, ParseError<()>>(|input| { input.expect_colon()?; - input.expect_ident_matching("host")?; - let mut invalid = false; + let Ok(next) = input.next() else { return Ok(()) }; + let mut invalid = match &*next { + Token::Ident(x) if x.as_bytes() == b"host" => None, + Token::Function(x) if x.as_bytes() == b"host" => Some(input.position()), + _ => { return Err(input.new_custom_error(())) } + }; let next = loop { let Ok(next) = input.next() else { return Ok(()) }; if *next != Token::CurlyBracketBlock { - invalid = true; - let pos = input.position(); - ss.add_warning( - error::ParseErrorKind::HostSelectorCombination, - pos..pos, - ); + if invalid.is_none() { + invalid = Some(input.position()); + } } else { break next; } }; - if !invalid { + if let Some(pos) = invalid { + ss.add_warning( + error::ParseErrorKind::HostSelectorCombination, + pos..pos, + ); + } else { ss.write_in_low_priority(input, |ss, input| { ss.append_token(StepToken::wrap_at(Token::SquareBracketBlock, &next), input, None); ss.append_token(StepToken::wrap_at(Token::Ident("is".into()), &next), input, None); @@ -883,6 +889,43 @@ mod test { ); } + #[test] + fn illegal_host_combination() { + let trans = StyleSheetTransformer::from_css( + "", + r#" + :host(.a) { + color: red; + } + :host .a { + color: red; + } + .a { color: green } + "#, + StyleSheetOptions { + host_is: Some("TEST".to_string()), + ..Default::default() + }, + ); + assert_eq!( + trans.warnings().map(|x| x.kind.clone()).collect::>(), + [error::ParseErrorKind::HostSelectorCombination, error::ParseErrorKind::HostSelectorCombination], + ); + let (output, lp) = trans.output_and_low_priority_output(); + let mut s = Vec::new(); + output.write(&mut s).unwrap(); + assert_eq!( + std::str::from_utf8(&s).unwrap(), + r#".a{color:green}"# + ); + let mut s = Vec::new(); + lp.write(&mut s).unwrap(); + assert_eq!( + std::str::from_utf8(&s).unwrap(), + r#""# + ); + } + #[test] fn host_select_inside_at_rules() { let trans = StyleSheetTransformer::from_css( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bbf2af8..d9b99a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -168,6 +168,9 @@ importers: glass-easel-miniprogram-webpack-plugin: dependencies: + chalk: + specifier: '4' + version: 4.1.2 chokidar: specifier: ^3.5.3 version: 3.5.3 @@ -1598,7 +1601,6 @@ packages: engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: true /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} @@ -1829,7 +1831,6 @@ packages: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true /char-regex@1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} @@ -1902,7 +1903,6 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: true /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} @@ -1911,7 +1911,6 @@ packages: /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true /colorette@2.0.19: resolution: {integrity: sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==} @@ -4727,7 +4726,6 @@ packages: engines: {node: '>=8'} dependencies: has-flag: 4.0.0 - dev: true /supports-color@8.1.1: resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==}