taste-lint 0.0.7 → 0.0.8

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.
package/dist/cli.js CHANGED
@@ -16,7 +16,7 @@ import { mdxjs } from "micromark-extension-mdxjs";
16
16
  import { styleText } from "node:util";
17
17
  import os from "node:os";
18
18
  //#region package.json
19
- var version = "0.0.7";
19
+ var version = "0.0.8";
20
20
  //#endregion
21
21
  //#region src/lib/stats.ts
22
22
  const makePRNG = (seed) => {
@@ -662,7 +662,7 @@ const stripVariants = (cls) => {
662
662
  };
663
663
  };
664
664
  const isColour = (token) => {
665
- if (token.startsWith("[#") || token.startsWith("[rgb") || token.startsWith("[hsl") || token.startsWith("[oklch") || token.startsWith("[var(")) return true;
665
+ if (token.startsWith("[#") || token.startsWith("[rgb") || token.startsWith("[hsl") || token.startsWith("[oklch") || token.startsWith("[oklab") || token.startsWith("[color:") || token.startsWith("(color:")) return true;
666
666
  return COLOUR_NAMES.has(token.replace(/-\d{2,3}$/, ""));
667
667
  };
668
668
  const resolveTypography = (classes, config) => {
@@ -681,7 +681,7 @@ const resolveTypography = (classes, config) => {
681
681
  if (variants.some((v) => !["dark"].includes(v))) continue;
682
682
  if (base.startsWith("text-")) {
683
683
  const [sizeToken, leadingToken] = base.slice(5).split("/");
684
- if (isColour(sizeToken)) {
684
+ if (!Object.hasOwn(theme, sizeToken) && isColour(sizeToken)) {
685
685
  out.colourClasses.push(cls);
686
686
  continue;
687
687
  }
@@ -700,21 +700,25 @@ const resolveTypography = (classes, config) => {
700
700
  "clip"
701
701
  ].includes(sizeToken)) continue;
702
702
  const known = FONT_SIZES[sizeToken];
703
- if (known) {
703
+ const declared = Object.hasOwn(theme, sizeToken);
704
+ const arbitrary = sizeToken.startsWith("[") && sizeToken.endsWith("]");
705
+ if (declared || arbitrary) {
706
+ const raw = declared ? theme[sizeToken] : sizeToken.slice(1, -1).replace(/^length:/u, "");
707
+ const px = parseLength(raw);
708
+ out.fontSizePx = px ?? void 0;
709
+ if (lineHeightFromSize) {
710
+ out.lineHeightPx = void 0;
711
+ out.lineHeight = void 0;
712
+ lineHeightFromSize = false;
713
+ }
714
+ if (px === null) out.unresolved.push(cls);
715
+ } else if (known) {
704
716
  out.fontSizePx = known[0];
705
717
  if (!leadingToken && (lineHeightFromSize || out.lineHeightPx === void 0 && out.lineHeight === void 0)) {
706
718
  out.lineHeightPx = known[1];
707
719
  out.lineHeight = void 0;
708
720
  lineHeightFromSize = true;
709
721
  }
710
- } else if (sizeToken.startsWith("[") && sizeToken.endsWith("]")) {
711
- const px = parseLength(sizeToken.slice(1, -1));
712
- if (px === null) out.unresolved.push(cls);
713
- else out.fontSizePx = px;
714
- } else if (theme[sizeToken]) {
715
- const px = parseLength(theme[sizeToken]);
716
- if (px === null) out.unresolved.push(cls);
717
- else out.fontSizePx = px;
718
722
  } else out.unresolved.push(cls);
719
723
  if (leadingToken) applyLeading(leadingToken, cls);
720
724
  continue;
@@ -2589,7 +2593,7 @@ const ARCHITECTURE_RULES = [
2589
2593
  const MODULE$1 = "src/rules/code/classes.ts";
2590
2594
  const ANIMATION = "skills/ui-animation/references";
2591
2595
  const bases = (unit) => (unit.classes ?? []).map(baseClass);
2592
- const animates = (list) => list.some((c) => c.startsWith("transition") || c.startsWith("duration-") || c.startsWith("animate-") && c !== "animate-none");
2596
+ const animates = (list) => list.some((c) => c.startsWith("transition") && c !== "transition-none" || c.startsWith("duration-") || c.startsWith("animate-") && c !== "animate-none");
2593
2597
  const durationMs = (cls) => {
2594
2598
  const named = cls.match(/^duration-(\d+)$/u);
2595
2599
  if (named) return Number(named[1]);
@@ -2675,7 +2679,7 @@ const CLASS_RULES = [
2675
2679
  categoryId: "easing-and-duration",
2676
2680
  check: (unit) => {
2677
2681
  const list = bases(unit);
2678
- if (!list.some((c) => c.startsWith("transition"))) return none;
2682
+ if (!list.some((c) => c.startsWith("transition") && c !== "transition-none")) return none;
2679
2683
  const slow = list.filter((c) => (durationMs(c) ?? 0) > 300);
2680
2684
  return slow.length > 0 ? hit(slow.join(" ")) : none;
2681
2685
  },
@@ -2744,13 +2748,18 @@ const CLASS_RULES = [
2744
2748
  shadcn({
2745
2749
  categoryId: "look-constraints",
2746
2750
  check: (unit) => {
2747
- const found = bases(unit).filter((c) => /-\[[^\]]+\]/u.test(c));
2751
+ const found = bases(unit).filter((c) => {
2752
+ const value = c.match(/^-?[\w-]+-\[(.+?)\](?:\/[^\s]+)?!?$/u)?.[1]?.replace(/^(?:length|color):/u, "");
2753
+ if (!value) return false;
2754
+ if (/var\(|env\(|theme\(|^--|^(?:calc|min|max|clamp|minmax|repeat|url)\(/u.test(value)) return false;
2755
+ return /^-?(?:\d+(?:\.\d+)?|\.\d+)(?:px|rem|em|ms|s|deg)?$/u.test(value) || /^#[\da-f]{3,8}$/iu.test(value) || /^(?:rgb|rgba|hsl|hsla|oklab|oklch|color)\(/u.test(value);
2756
+ });
2748
2757
  return found.length > 0 ? hit(found.join(" ")) : none;
2749
2758
  },
2750
- hint: "Step the scale (p-3, text-sm, rounded-md) or register the value in the theme so the next component can reach it by name. p-[13px] is a nudge, not a decision.",
2759
+ hint: "Review whether an existing token serves this literal value. Keep deliberate layout, asset and optical constraints; register a recurring design value if useful. This syntax check does not establish a defect or a safe replacement.",
2751
2760
  id: "craft-arbitrary-value-class",
2752
2761
  ruleId: "shadcn/no-arbitrary-values",
2753
- title: "Arbitrary value in a utility class"
2762
+ title: "Literal arbitrary utility value to review"
2754
2763
  }),
2755
2764
  shadcn({
2756
2765
  categoryId: "look-constraints",
@@ -5831,6 +5840,14 @@ const artifacts = [
5831
5840
  "**/docs/archive/**",
5832
5841
  "**/.captain/**"
5833
5842
  ];
5843
+ const stylePreferences = [
5844
+ "copywriting-long-sentence",
5845
+ "typography-straight-quotes",
5846
+ "typography-ellipsis",
5847
+ "typography-dashes",
5848
+ "typography-midpoint-separators",
5849
+ "typography-line-height-out-of-band"
5850
+ ];
5834
5851
  const internal = [
5835
5852
  "**/.claude/**",
5836
5853
  "**/.agents/**",
@@ -5875,6 +5892,7 @@ const profileFor = (name) => {
5875
5892
  };
5876
5893
  case "product": return {
5877
5894
  ...common,
5895
+ advisory: stylePreferences,
5878
5896
  exclude: [
5879
5897
  ...artifacts,
5880
5898
  ...internal,
@@ -5885,7 +5903,7 @@ const profileFor = (name) => {
5885
5903
  };
5886
5904
  case "writing": return {
5887
5905
  ...common,
5888
- advisory: ["copywriting-long-sentence", "typography-straight-quotes"],
5906
+ advisory: stylePreferences,
5889
5907
  docTypes: [{
5890
5908
  glob: "**/content/writing/**/*.{md,mdx}",
5891
5909
  type: "personal"
@@ -5905,7 +5923,7 @@ const profileFor = (name) => {
5905
5923
  };
5906
5924
  case "instructions": return {
5907
5925
  ...common,
5908
- advisory: ["copywriting-long-sentence", "typography-straight-quotes"],
5926
+ advisory: stylePreferences,
5909
5927
  include: [...internal, "**/docs/plans/**/*.md"],
5910
5928
  objective: "Review repository instructions, skill authoring, and implementation plans"
5911
5929
  };
@@ -6302,6 +6320,7 @@ const runScan = async (options, ctx = {}) => {
6302
6320
  ...config,
6303
6321
  root: void 0
6304
6322
  },
6323
+ engineVersion: version,
6305
6324
  exclude,
6306
6325
  graph: graph?.digest,
6307
6326
  model: options.model ?? "jev-latest",