tutuca 0.9.91 → 0.9.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -12963,6 +12963,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
12963
12963
  checkProvidesAreAddressable(lx, Comp);
12964
12964
  checkLookupShapes(lx, Comp);
12965
12965
  checkHandlersNotAsync(lx, Comp);
12966
+ checkScopedStyleTopLevel(lx, Comp);
12966
12967
  const referencedAlters = new Set;
12967
12968
  const referencedInputs = new Set;
12968
12969
  const referencedDynamics = new Set;
@@ -13376,6 +13377,64 @@ function checkHandlersNotAsync(lx, Comp) {
13376
13377
  }
13377
13378
  }
13378
13379
  }
13380
+ function blankCssNoise(css) {
13381
+ return css.replace(/\/\*[\s\S]*?\*\//g, blankRun).replace(/"(?:[^"\\\n]|\\.)*"/g, blankRun).replace(/'(?:[^'\\\n]|\\.)*'/g, blankRun);
13382
+ }
13383
+ function offsetToLineCol2(str, index) {
13384
+ let line = 1;
13385
+ let lineStart = 0;
13386
+ for (let i = 0;i < index; i++) {
13387
+ if (str[i] === `
13388
+ `) {
13389
+ line++;
13390
+ lineStart = i + 1;
13391
+ }
13392
+ }
13393
+ return { line, column: index - lineStart + 1 };
13394
+ }
13395
+ function suppressedLines(css) {
13396
+ const lines = new Set;
13397
+ IGNORE_DIRECTIVE.lastIndex = 0;
13398
+ for (let m = IGNORE_DIRECTIVE.exec(css);m !== null; m = IGNORE_DIRECTIVE.exec(css)) {
13399
+ lines.add(offsetToLineCol2(css, m.index).line);
13400
+ }
13401
+ return lines;
13402
+ }
13403
+ function scanScopedCss(lx, css, key) {
13404
+ if (!css)
13405
+ return;
13406
+ const ignore = suppressedLines(css);
13407
+ const clean = blankCssNoise(css);
13408
+ const report = (id, info) => {
13409
+ if (ignore.has(info.location.line))
13410
+ return;
13411
+ lx.error(id, { key, ...info }, { kind: "rephrase", text: STYLE_TO_GLOBAL_HELP });
13412
+ };
13413
+ NON_NESTABLE_AT_RULE.lastIndex = 0;
13414
+ for (let m = NON_NESTABLE_AT_RULE.exec(clean);m !== null; m = NON_NESTABLE_AT_RULE.exec(clean)) {
13415
+ const at = m.index + m[0].indexOf("@");
13416
+ report(TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE, {
13417
+ atRule: m[1].toLowerCase(),
13418
+ location: offsetToLineCol2(clean, at)
13419
+ });
13420
+ }
13421
+ GLOBAL_LEADING_SELECTOR.lastIndex = 0;
13422
+ for (let m = GLOBAL_LEADING_SELECTOR.exec(clean);m !== null; m = GLOBAL_LEADING_SELECTOR.exec(clean)) {
13423
+ const at = m.index + m[0].indexOf(m[1]);
13424
+ report(GLOBAL_SELECTOR_IN_SCOPED_STYLE, {
13425
+ selector: m[1].toLowerCase(),
13426
+ location: offsetToLineCol2(clean, at)
13427
+ });
13428
+ }
13429
+ }
13430
+ function checkScopedStyleTopLevel(lx, Comp) {
13431
+ scanScopedCss(lx, Comp.commonStyle, "commonStyle");
13432
+ for (const name in Comp.views) {
13433
+ const { style } = Comp.views[name];
13434
+ if (style)
13435
+ lx.push({ viewName: name }, () => scanScopedCss(lx, style, "style"));
13436
+ }
13437
+ }
13379
13438
  function checkProvidesAreAddressable(lx, Comp) {
13380
13439
  for (const name in Comp._rawProvide) {
13381
13440
  if (Comp.provide[name] === undefined) {
@@ -13452,7 +13511,7 @@ class LintContext {
13452
13511
  this.reports.push({ id, info, level, context: { ...this.frame }, suggestion });
13453
13512
  }
13454
13513
  }
13455
- var KNOWN_COMPONENT_SPEC_KEYS, EMPTY_SET2, FRAMEWORK_WELL_KNOWN_EXTRAS, KNOWN_DIRECTIVE_NAMES, ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED", DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED", PROVIDE_NOT_ADDRESSABLE = "PROVIDE_NOT_ADDRESSABLE", LOOKUP_BAD_SHAPE = "LOOKUP_BAD_SHAPE", LOOKUP_TARGET_MALFORMED = "LOOKUP_TARGET_MALFORMED", RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP", UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER", UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME", INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED", INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED", INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED", INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD", INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER", FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED", FIELD_VAL_IS_METHOD = "FIELD_VAL_IS_METHOD", METHOD_VAL_NOT_DEFINED = "METHOD_VAL_NOT_DEFINED", METHOD_VAL_IS_FIELD = "METHOD_VAL_IS_FIELD", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET", UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME", UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME", UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG", UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE", UNKNOWN_X_OP = "UNKNOWN_X_OP", UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR", MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX", MAYBE_ADD_AT_PREFIX = "MAYBE_ADD_AT_PREFIX", BAD_VALUE = "BAD_VALUE", UNSUPPORTED_EXPR_SYNTAX = "UNSUPPORTED_EXPR_SYNTAX", REDUNDANT_TEMPLATE_STRING = "REDUNDANT_TEMPLATE_STRING", PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING", UNKNOWN_COMPONENT_SPEC_KEY = "UNKNOWN_COMPONENT_SPEC_KEY", COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE", ASYNC_HANDLER = "ASYNC_HANDLER", X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, HOST_DIRECTIVE_ONLY_NAMES, LEVEL_WARN2 = "warn", LEVEL_ERROR2 = "error", LEVEL_HINT = "hint", PARSE_ISSUES, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS, KNOWN_HANDLER_NAMES, fixTo = (from, to) => ({ kind: "rewrite", from, to }), ATTR_VAL_CHECKERS, NODE_KIND_TO_CTX, HANDLER_CHANNELS, ASYNC_HANDLER_HELP, KNOWN_LOOKUP_KEYS, LintParseContext;
13514
+ var KNOWN_COMPONENT_SPEC_KEYS, EMPTY_SET2, FRAMEWORK_WELL_KNOWN_EXTRAS, KNOWN_DIRECTIVE_NAMES, ALT_HANDLER_NOT_DEFINED = "ALT_HANDLER_NOT_DEFINED", ALT_HANDLER_NOT_REFERENCED = "ALT_HANDLER_NOT_REFERENCED", DYN_VAL_NOT_DEFINED = "DYN_VAL_NOT_DEFINED", DYN_ALIAS_NOT_REFERENCED = "DYN_ALIAS_NOT_REFERENCED", PROVIDE_NOT_ADDRESSABLE = "PROVIDE_NOT_ADDRESSABLE", LOOKUP_BAD_SHAPE = "LOOKUP_BAD_SHAPE", LOOKUP_TARGET_MALFORMED = "LOOKUP_TARGET_MALFORMED", RENDER_IT_OUTSIDE_OF_LOOP = "RENDER_IT_OUTSIDE_OF_LOOP", UNKNOWN_EVENT_MODIFIER = "UNKNOWN_EVENT_MODIFIER", UNKNOWN_HANDLER_ARG_NAME = "UNKNOWN_HANDLER_ARG_NAME", INPUT_HANDLER_NOT_IMPLEMENTED = "INPUT_HANDLER_NOT_IMPLEMENTED", INPUT_HANDLER_NOT_REFERENCED = "INPUT_HANDLER_NOT_REFERENCED", INPUT_HANDLER_METHOD_NOT_IMPLEMENTED = "INPUT_HANDLER_METHOD_NOT_IMPLEMENTED", INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD = "INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD", INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER = "INPUT_HANDLER_METHOD_FOR_INPUT_HANDLER", FIELD_VAL_NOT_DEFINED = "FIELD_VAL_NOT_DEFINED", FIELD_VAL_IS_METHOD = "FIELD_VAL_IS_METHOD", METHOD_VAL_NOT_DEFINED = "METHOD_VAL_NOT_DEFINED", METHOD_VAL_IS_FIELD = "METHOD_VAL_IS_FIELD", DUPLICATE_ATTR_DEFINITION = "DUPLICATE_ATTR_DEFINITION", IF_NO_BRANCH_SET = "IF_NO_BRANCH_SET", UNKNOWN_REQUEST_NAME = "UNKNOWN_REQUEST_NAME", UNKNOWN_COMPONENT_NAME = "UNKNOWN_COMPONENT_NAME", UNKNOWN_MACRO_ARG = "UNKNOWN_MACRO_ARG", UNKNOWN_DIRECTIVE = "UNKNOWN_DIRECTIVE", UNKNOWN_X_OP = "UNKNOWN_X_OP", UNKNOWN_X_ATTR = "UNKNOWN_X_ATTR", MAYBE_DROP_AT_PREFIX = "MAYBE_DROP_AT_PREFIX", MAYBE_ADD_AT_PREFIX = "MAYBE_ADD_AT_PREFIX", BAD_VALUE = "BAD_VALUE", UNSUPPORTED_EXPR_SYNTAX = "UNSUPPORTED_EXPR_SYNTAX", REDUNDANT_TEMPLATE_STRING = "REDUNDANT_TEMPLATE_STRING", PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING", UNKNOWN_COMPONENT_SPEC_KEY = "UNKNOWN_COMPONENT_SPEC_KEY", COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE", ASYNC_HANDLER = "ASYNC_HANDLER", TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE = "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE", GLOBAL_SELECTOR_IN_SCOPED_STYLE = "GLOBAL_SELECTOR_IN_SCOPED_STYLE", X_KNOWN_OP_NAMES, X_KNOWN_ATTR_NAMES, HOST_DIRECTIVE_ONLY_NAMES, LEVEL_WARN2 = "warn", LEVEL_ERROR2 = "error", LEVEL_HINT = "hint", PARSE_ISSUES, UNSUPPORTED_EXPR_GUIDANCE, HTML_LINT_OPTS, NO_WRAPPERS, KNOWN_HANDLER_NAMES, fixTo = (from, to) => ({ kind: "rewrite", from, to }), ATTR_VAL_CHECKERS, NODE_KIND_TO_CTX, HANDLER_CHANNELS, ASYNC_HANDLER_HELP, NON_NESTABLE_AT_RULE, GLOBAL_LEADING_SELECTOR, IGNORE_DIRECTIVE, blankRun = (m) => m.replace(/[^\n]/g, " "), STYLE_TO_GLOBAL_HELP, KNOWN_LOOKUP_KEYS, LintParseContext;
13456
13515
  var init_lint_check = __esm(() => {
13457
13516
  init_anode();
13458
13517
  init_htmllinter();
@@ -13603,6 +13662,10 @@ var init_lint_check = __esm(() => {
13603
13662
  };
13604
13663
  HANDLER_CHANNELS = ["input", "receive", "bubble", "response", "alter"];
13605
13664
  ASYNC_HANDLER_HELP = "Move the async work into a request handler and trigger it with " + "ctx.request('name', args), then handle the result in a synchronous response " + "handler. To coordinate other components, keep the handler synchronous and use " + "ctx.send to deliver a message or ctx.bubble to raise an event.";
13665
+ NON_NESTABLE_AT_RULE = /(?:^|[\s;{}])@(?:-[a-z]+-)?(charset|import|namespace|font-face|keyframes|page|property|counter-style|font-feature-values|font-palette-values|view-transition)\b/gi;
13666
+ GLOBAL_LEADING_SELECTOR = /(?:^|[{}])\s*(html|body|:root)\b[^{};]*\{/gi;
13667
+ IGNORE_DIRECTIVE = /\/\*\s*tutuca-lint-ignore\s*\*\//g;
13668
+ STYLE_TO_GLOBAL_HELP = "Move it to the component's 'globalStyle' key, which is injected without the " + "component-scoping wrapper. To suppress a false positive, put a " + "/* tutuca-lint-ignore */ comment on the same line.";
13606
13669
  KNOWN_LOOKUP_KEYS = new Set(["for", "default"]);
13607
13670
  LintParseContext = class LintParseContext extends ParseContext {
13608
13671
  constructor(document2, Text, Comment) {
@@ -15103,6 +15166,18 @@ var init_lint_rules = __esm(() => {
15103
15166
  group: "Handler effects",
15104
15167
  summary: "A handler in `input`/`receive`/`bubble`/`response`/`alter` is an async " + "function — handlers must be synchronous; use a request handler, `ctx.send`, " + "or `ctx.bubble` instead."
15105
15168
  },
15169
+ {
15170
+ code: TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE,
15171
+ level: "error",
15172
+ group: "Component styles",
15173
+ summary: "A top-level-only at-rule (`@import`, `@keyframes`, `@font-face`, …) appears " + "in `style`/`commonStyle`, which is wrapped in a component-scoped selector " + "where it is invalid and dropped — move it to `globalStyle`."
15174
+ },
15175
+ {
15176
+ code: GLOBAL_SELECTOR_IN_SCOPED_STYLE,
15177
+ level: "error",
15178
+ group: "Component styles",
15179
+ summary: "A rule whose leading selector is `html`/`body`/`:root` appears in " + "`style`/`commonStyle`; once scoped it becomes a descendant selector that " + "never matches — move it to `globalStyle`."
15180
+ },
15106
15181
  {
15107
15182
  code: COMP_FIELD_BAD_SHAPE,
15108
15183
  level: "error",
@@ -15298,6 +15373,10 @@ function lintIdToMessage(id, info) {
15298
15373
  return `MathML attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
15299
15374
  case "ASYNC_HANDLER":
15300
15375
  return `Handler '${info.name}' in '${info.channel}' is an async function — handlers must be synchronous and return the updated state (an async function returns a Promise the framework won't await)`;
15376
+ case "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE":
15377
+ return `'@${info.atRule}' is a top-level-only at-rule, but '${info.key}' is wrapped in a component-scoped selector ([data-cid=…]{…}) where it is invalid and silently dropped — move it to 'globalStyle'${fmtLocationSuffix(info)}`;
15378
+ case "GLOBAL_SELECTOR_IN_SCOPED_STYLE":
15379
+ return `Selector '${info.selector}' targets the document root, but '${info.key}' is wrapped in a component-scoped selector, so it becomes a descendant selector that never matches — move it to 'globalStyle'${fmtLocationSuffix(info)}`;
15301
15380
  case "LINT_ERROR":
15302
15381
  return info.message;
15303
15382
  default:
@@ -5033,6 +5033,8 @@ var PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING";
5033
5033
  var UNKNOWN_COMPONENT_SPEC_KEY = "UNKNOWN_COMPONENT_SPEC_KEY";
5034
5034
  var COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE";
5035
5035
  var ASYNC_HANDLER = "ASYNC_HANDLER";
5036
+ var TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE = "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE";
5037
+ var GLOBAL_SELECTOR_IN_SCOPED_STYLE = "GLOBAL_SELECTOR_IN_SCOPED_STYLE";
5036
5038
  var X_KNOWN_OP_NAMES = new Set([
5037
5039
  "slot",
5038
5040
  "text",
@@ -5124,6 +5126,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
5124
5126
  checkProvidesAreAddressable(lx, Comp);
5125
5127
  checkLookupShapes(lx, Comp);
5126
5128
  checkHandlersNotAsync(lx, Comp);
5129
+ checkScopedStyleTopLevel(lx, Comp);
5127
5130
  const referencedAlters = new Set;
5128
5131
  const referencedInputs = new Set;
5129
5132
  const referencedDynamics = new Set;
@@ -5641,6 +5644,69 @@ function checkHandlersNotAsync(lx, Comp) {
5641
5644
  }
5642
5645
  }
5643
5646
  }
5647
+ var NON_NESTABLE_AT_RULE = /(?:^|[\s;{}])@(?:-[a-z]+-)?(charset|import|namespace|font-face|keyframes|page|property|counter-style|font-feature-values|font-palette-values|view-transition)\b/gi;
5648
+ var GLOBAL_LEADING_SELECTOR = /(?:^|[{}])\s*(html|body|:root)\b[^{};]*\{/gi;
5649
+ var IGNORE_DIRECTIVE = /\/\*\s*tutuca-lint-ignore\s*\*\//g;
5650
+ var blankRun = (m) => m.replace(/[^\n]/g, " ");
5651
+ function blankCssNoise(css) {
5652
+ return css.replace(/\/\*[\s\S]*?\*\//g, blankRun).replace(/"(?:[^"\\\n]|\\.)*"/g, blankRun).replace(/'(?:[^'\\\n]|\\.)*'/g, blankRun);
5653
+ }
5654
+ function offsetToLineCol2(str, index) {
5655
+ let line = 1;
5656
+ let lineStart = 0;
5657
+ for (let i = 0;i < index; i++) {
5658
+ if (str[i] === `
5659
+ `) {
5660
+ line++;
5661
+ lineStart = i + 1;
5662
+ }
5663
+ }
5664
+ return { line, column: index - lineStart + 1 };
5665
+ }
5666
+ function suppressedLines(css) {
5667
+ const lines = new Set;
5668
+ IGNORE_DIRECTIVE.lastIndex = 0;
5669
+ for (let m = IGNORE_DIRECTIVE.exec(css);m !== null; m = IGNORE_DIRECTIVE.exec(css)) {
5670
+ lines.add(offsetToLineCol2(css, m.index).line);
5671
+ }
5672
+ return lines;
5673
+ }
5674
+ var STYLE_TO_GLOBAL_HELP = "Move it to the component's 'globalStyle' key, which is injected without the " + "component-scoping wrapper. To suppress a false positive, put a " + "/* tutuca-lint-ignore */ comment on the same line.";
5675
+ function scanScopedCss(lx, css, key) {
5676
+ if (!css)
5677
+ return;
5678
+ const ignore = suppressedLines(css);
5679
+ const clean = blankCssNoise(css);
5680
+ const report = (id, info) => {
5681
+ if (ignore.has(info.location.line))
5682
+ return;
5683
+ lx.error(id, { key, ...info }, { kind: "rephrase", text: STYLE_TO_GLOBAL_HELP });
5684
+ };
5685
+ NON_NESTABLE_AT_RULE.lastIndex = 0;
5686
+ for (let m = NON_NESTABLE_AT_RULE.exec(clean);m !== null; m = NON_NESTABLE_AT_RULE.exec(clean)) {
5687
+ const at = m.index + m[0].indexOf("@");
5688
+ report(TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE, {
5689
+ atRule: m[1].toLowerCase(),
5690
+ location: offsetToLineCol2(clean, at)
5691
+ });
5692
+ }
5693
+ GLOBAL_LEADING_SELECTOR.lastIndex = 0;
5694
+ for (let m = GLOBAL_LEADING_SELECTOR.exec(clean);m !== null; m = GLOBAL_LEADING_SELECTOR.exec(clean)) {
5695
+ const at = m.index + m[0].indexOf(m[1]);
5696
+ report(GLOBAL_SELECTOR_IN_SCOPED_STYLE, {
5697
+ selector: m[1].toLowerCase(),
5698
+ location: offsetToLineCol2(clean, at)
5699
+ });
5700
+ }
5701
+ }
5702
+ function checkScopedStyleTopLevel(lx, Comp) {
5703
+ scanScopedCss(lx, Comp.commonStyle, "commonStyle");
5704
+ for (const name in Comp.views) {
5705
+ const { style } = Comp.views[name];
5706
+ if (style)
5707
+ lx.push({ viewName: name }, () => scanScopedCss(lx, style, "style"));
5708
+ }
5709
+ }
5644
5710
  function checkProvidesAreAddressable(lx, Comp) {
5645
5711
  for (const name in Comp._rawProvide) {
5646
5712
  if (Comp.provide[name] === undefined) {
@@ -6357,6 +6423,10 @@ function lintIdToMessage(id, info) {
6357
6423
  return `MathML attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
6358
6424
  case "ASYNC_HANDLER":
6359
6425
  return `Handler '${info.name}' in '${info.channel}' is an async function — handlers must be synchronous and return the updated state (an async function returns a Promise the framework won't await)`;
6426
+ case "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE":
6427
+ return `'@${info.atRule}' is a top-level-only at-rule, but '${info.key}' is wrapped in a component-scoped selector ([data-cid=…]{…}) where it is invalid and silently dropped — move it to 'globalStyle'${fmtLocationSuffix(info)}`;
6428
+ case "GLOBAL_SELECTOR_IN_SCOPED_STYLE":
6429
+ return `Selector '${info.selector}' targets the document root, but '${info.key}' is wrapped in a component-scoped selector, so it becomes a descendant selector that never matches — move it to 'globalStyle'${fmtLocationSuffix(info)}`;
6360
6430
  case "LINT_ERROR":
6361
6431
  return info.message;
6362
6432
  default:
@@ -8198,6 +8268,7 @@ export {
8198
8268
  TestReport,
8199
8269
  TestIndex,
8200
8270
  Test,
8271
+ TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE,
8201
8272
  Stack2 as Stack,
8202
8273
  Set2 as Set,
8203
8274
  Seq,
@@ -8242,6 +8313,7 @@ export {
8242
8313
  INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD,
8243
8314
  Map3 as IMap,
8244
8315
  IF_NO_BRANCH_SET,
8316
+ GLOBAL_SELECTOR_IN_SCOPED_STYLE,
8245
8317
  FIELD_VAL_NOT_DEFINED,
8246
8318
  FIELD_VAL_IS_METHOD,
8247
8319
  FIELD_CLASS,
@@ -12684,6 +12684,8 @@ var PLACEHOLDERLESS_TEMPLATE_STRING = "PLACEHOLDERLESS_TEMPLATE_STRING";
12684
12684
  var UNKNOWN_COMPONENT_SPEC_KEY = "UNKNOWN_COMPONENT_SPEC_KEY";
12685
12685
  var COMP_FIELD_BAD_SHAPE = "COMP_FIELD_BAD_SHAPE";
12686
12686
  var ASYNC_HANDLER = "ASYNC_HANDLER";
12687
+ var TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE = "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE";
12688
+ var GLOBAL_SELECTOR_IN_SCOPED_STYLE = "GLOBAL_SELECTOR_IN_SCOPED_STYLE";
12687
12689
  var X_KNOWN_OP_NAMES = new Set([
12688
12690
  "slot",
12689
12691
  "text",
@@ -12775,6 +12777,7 @@ function checkComponent(Comp, lx = new LintContext, { wellKnownExtras = EMPTY_SE
12775
12777
  checkProvidesAreAddressable(lx, Comp);
12776
12778
  checkLookupShapes(lx, Comp);
12777
12779
  checkHandlersNotAsync(lx, Comp);
12780
+ checkScopedStyleTopLevel(lx, Comp);
12778
12781
  const referencedAlters = new Set;
12779
12782
  const referencedInputs = new Set;
12780
12783
  const referencedDynamics = new Set;
@@ -13292,6 +13295,69 @@ function checkHandlersNotAsync(lx, Comp) {
13292
13295
  }
13293
13296
  }
13294
13297
  }
13298
+ var NON_NESTABLE_AT_RULE = /(?:^|[\s;{}])@(?:-[a-z]+-)?(charset|import|namespace|font-face|keyframes|page|property|counter-style|font-feature-values|font-palette-values|view-transition)\b/gi;
13299
+ var GLOBAL_LEADING_SELECTOR = /(?:^|[{}])\s*(html|body|:root)\b[^{};]*\{/gi;
13300
+ var IGNORE_DIRECTIVE = /\/\*\s*tutuca-lint-ignore\s*\*\//g;
13301
+ var blankRun = (m) => m.replace(/[^\n]/g, " ");
13302
+ function blankCssNoise(css) {
13303
+ return css.replace(/\/\*[\s\S]*?\*\//g, blankRun).replace(/"(?:[^"\\\n]|\\.)*"/g, blankRun).replace(/'(?:[^'\\\n]|\\.)*'/g, blankRun);
13304
+ }
13305
+ function offsetToLineCol2(str, index) {
13306
+ let line = 1;
13307
+ let lineStart = 0;
13308
+ for (let i = 0;i < index; i++) {
13309
+ if (str[i] === `
13310
+ `) {
13311
+ line++;
13312
+ lineStart = i + 1;
13313
+ }
13314
+ }
13315
+ return { line, column: index - lineStart + 1 };
13316
+ }
13317
+ function suppressedLines(css) {
13318
+ const lines = new Set;
13319
+ IGNORE_DIRECTIVE.lastIndex = 0;
13320
+ for (let m = IGNORE_DIRECTIVE.exec(css);m !== null; m = IGNORE_DIRECTIVE.exec(css)) {
13321
+ lines.add(offsetToLineCol2(css, m.index).line);
13322
+ }
13323
+ return lines;
13324
+ }
13325
+ var STYLE_TO_GLOBAL_HELP = "Move it to the component's 'globalStyle' key, which is injected without the " + "component-scoping wrapper. To suppress a false positive, put a " + "/* tutuca-lint-ignore */ comment on the same line.";
13326
+ function scanScopedCss(lx, css, key) {
13327
+ if (!css)
13328
+ return;
13329
+ const ignore = suppressedLines(css);
13330
+ const clean = blankCssNoise(css);
13331
+ const report = (id, info) => {
13332
+ if (ignore.has(info.location.line))
13333
+ return;
13334
+ lx.error(id, { key, ...info }, { kind: "rephrase", text: STYLE_TO_GLOBAL_HELP });
13335
+ };
13336
+ NON_NESTABLE_AT_RULE.lastIndex = 0;
13337
+ for (let m = NON_NESTABLE_AT_RULE.exec(clean);m !== null; m = NON_NESTABLE_AT_RULE.exec(clean)) {
13338
+ const at = m.index + m[0].indexOf("@");
13339
+ report(TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE, {
13340
+ atRule: m[1].toLowerCase(),
13341
+ location: offsetToLineCol2(clean, at)
13342
+ });
13343
+ }
13344
+ GLOBAL_LEADING_SELECTOR.lastIndex = 0;
13345
+ for (let m = GLOBAL_LEADING_SELECTOR.exec(clean);m !== null; m = GLOBAL_LEADING_SELECTOR.exec(clean)) {
13346
+ const at = m.index + m[0].indexOf(m[1]);
13347
+ report(GLOBAL_SELECTOR_IN_SCOPED_STYLE, {
13348
+ selector: m[1].toLowerCase(),
13349
+ location: offsetToLineCol2(clean, at)
13350
+ });
13351
+ }
13352
+ }
13353
+ function checkScopedStyleTopLevel(lx, Comp) {
13354
+ scanScopedCss(lx, Comp.commonStyle, "commonStyle");
13355
+ for (const name in Comp.views) {
13356
+ const { style } = Comp.views[name];
13357
+ if (style)
13358
+ lx.push({ viewName: name }, () => scanScopedCss(lx, style, "style"));
13359
+ }
13360
+ }
13295
13361
  function checkProvidesAreAddressable(lx, Comp) {
13296
13362
  for (const name in Comp._rawProvide) {
13297
13363
  if (Comp.provide[name] === undefined) {
@@ -14008,6 +14074,10 @@ function lintIdToMessage(id, info) {
14008
14074
  return `MathML attribute '${info.raw}' will be rewritten to '${info.canonical}'${fmtLocationSuffix(info)}`;
14009
14075
  case "ASYNC_HANDLER":
14010
14076
  return `Handler '${info.name}' in '${info.channel}' is an async function — handlers must be synchronous and return the updated state (an async function returns a Promise the framework won't await)`;
14077
+ case "TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE":
14078
+ return `'@${info.atRule}' is a top-level-only at-rule, but '${info.key}' is wrapped in a component-scoped selector ([data-cid=…]{…}) where it is invalid and silently dropped — move it to 'globalStyle'${fmtLocationSuffix(info)}`;
14079
+ case "GLOBAL_SELECTOR_IN_SCOPED_STYLE":
14080
+ return `Selector '${info.selector}' targets the document root, but '${info.key}' is wrapped in a component-scoped selector, so it becomes a descendant selector that never matches — move it to 'globalStyle'${fmtLocationSuffix(info)}`;
14011
14081
  case "LINT_ERROR":
14012
14082
  return info.message;
14013
14083
  default:
@@ -15792,6 +15862,7 @@ export {
15792
15862
  TestReport,
15793
15863
  TestIndex,
15794
15864
  Test,
15865
+ TOP_LEVEL_AT_RULE_IN_SCOPED_STYLE,
15795
15866
  Stack,
15796
15867
  Set2 as Set,
15797
15868
  Seq,
@@ -15836,6 +15907,7 @@ export {
15836
15907
  INPUT_HANDLER_FOR_INPUT_HANDLER_METHOD,
15837
15908
  Map2 as IMap,
15838
15909
  IF_NO_BRANCH_SET,
15910
+ GLOBAL_SELECTOR_IN_SCOPED_STYLE,
15839
15911
  FIELD_VAL_NOT_DEFINED,
15840
15912
  FIELD_VAL_IS_METHOD,
15841
15913
  FIELD_CLASS,