Repository navigation
fix: package mode: theme partials, subpath exports with no file, dist-only message - #250
Merged
Merged
Conversation
…-only message A design-system package whose tokens are a Tailwind v4 theme partial (@theme, no @import "tailwindcss", since the app imports Tailwind) gave its apps no spacing token, so no-hardcoded-spacing went quiet and p-[13px] was not reported. loadTokens now gives such a partial Tailwind's default spacing unit and radius scale when the project depends on Tailwind, unless the partial clears them. In a workspace app, <Tooltip> from @acme/ui/components/tooltip, where "./components/*" maps onto src/components/*.tsx and there is no tooltip.tsx, was said to be unchecked, with advice to add the missing files to "components". An export that maps a specifier onto a source file that is not there now means no such module, and no-unknown-component reports it. An export that comes first and leads to dist/, not built yet, still leaves it unchecked. list_components and inspect --explain, in an app whose installed package publishes neither component sources nor type declarations, say so and what its team can do, instead of pointing at the components globs. renderNotFound drops "Available: ." for an empty list. init adds ONSYSTEM.md to "files" next to the config, so apps that install the package get the guide.
…'s files note
- An import through an export into a build folder is no longer reported as
no-unknown-component when its source has another name: with
"./*": { types: "./dist/components/*.d.ts", default: "./dist/components/*.js" }
and src/components/tooltip.ts, <Tooltip> from @acme/ui/tooltip is said
not to have been checked, built or not, linked or not. The decision now
comes from the package's exports as its package.json writes them
(exportedTargets in src/detect.ts), not from config.imports, which maps
dist/ back to src/*.tsx. Only an entry whose targets are all source
files, none on disk, is reported.
- The package is found past a package.json with no name in its folders
({"type": "module"} in src/components).
- With "libraries": false in the app's config and a package that publishes
type declarations, list_components, get_component and inspect --explain
say that "libraries": false turned them off, and that [] reads them.
- get_component gives the same reason as list_components when there are
no components.
- A theme partial gets Tailwind's default spacing unit and radius scale
only on Tailwind v4: not with tailwindcss ^3, ~3 or 3.x, unless
@tailwindcss/postcss, /vite or /cli is listed.
- init names only the files it added to "files", and leaves ONSYSTEM.md
out when "files" excludes it ("!ONSYSTEM.md").
- The changeset, docs/design-system-packages.md and docs/rules.md say so.
…rgets - exportMatches orders two patterns with the same prefix by key length, as Node.js's PATTERN_KEY_COMPARE does, and a pattern's * stands for at least one character. With "./components/*": "./src/components/*.tsx" and "./components/*.js" into dist/components, in either order, <Tip> from "@acme/ui/components/tip.js" resolves to dist/components/tip.js, as Node.js resolves it, and is no longer reported as no-unknown-component. - A .jsx export target counts as there when the .tsx file TypeScript reads for it is. - A target in a build folder (dist, build, lib, out, esm, cjs) is never taken for a missing source file, whatever its extension: an unbuilt "./*": "./dist/*.tsx" stays unchecked, as the docs say.
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Roadmap item: OS2-77 (package-mode correctness: theme partials, subpath imports, one dist-only message).
What was wrong
no-hardcoded-spacingin every app. A Tailwind v4 design-system package ships a theme that does not@import "tailwindcss"(the app does). When an app takes on the package's config, those tokens replace the app's own stylesheet, so no spacing token exists and the rule is skipped. In an installed app on@northwind/ui(tokens["theme.css"], a partial),p-[13px]was not reported. The same app with its own config naming both stylesheets reports it, withp-3as the nearest step."./components/*": "./src/components/*.tsx"and nosrc/components/tooltip.tsx,<Tooltip>from@acme/ui/components/tooltipwas not reported.checksaid instead:Extraction looks incomplete: ... add the missing files to "components" in the config. The file does not exist, so the import cannot compile. The same import from the package installed innode_moduleswas already reported, so the two layouts disagreed. Cause:outsideModelinsrc/lint/target.tstreated any module declared inexportsbut not on disk as possibly real.list_componentsandget_componentpointed at the wrong fix. They saidCheck the "components" globs in the config. The app has no config. The cause is that the package publishes neither its component sources nor type declarations, and writing an app config to follow that advice loses the package's tokens.initwroteONSYSTEM.md"for the apps' teams" but left it out offiles, so apps that install the package never got it.What changed
src/tokens/index.ts: some token stylesheets may be a Tailwind v4 theme (@theme) where none imports Tailwind. If the project is on Tailwind v4, the theme now gets Tailwind's default spacing unit and radius scale, as a stylesheet that imports Tailwind does. On v4 means:@tailwindcss/postcss,@tailwindcss/viteor@tailwindcss/cliin itspackage.json, ortailwindcssin a range that is not v3's (^3,~3,3.x). Tailwind v3 has no--spacingand norounded-xsorrounded-4xl, and its plugins (@tailwindcss/typography) run on either version, so they do not count. If the theme clears the defaults (--spacing-*: initial), it gets none. Of the finding's two proposals, I took "treat an app on Tailwind v4 as having the default--spacing". The other, reading the app's zero-config stylesheet, would needsrc/config.tsandsrc/design-system.ts, which fix(server): retry failed loads, reload JS configs, answer per path when --root holds projects #242 has open. The rootpackage.jsonis already in the model's cache key.src/lint/target.ts: an import with no file behind it now counts as invented in one case. The package'sexports, as itspackage.jsonwrites them, map it onto source files only (.ts/.tsx, or.jsxoutside a build folder), and none of them is on disk.no-unknown-componentreports it. The entry is the one Node.js picks, and its targets are every condition buttypes(exportedTargets, a new helper insrc/detect.tsbuilt on the existingexportMatches). Node.js picks an exact subpath, else the pattern with the longest prefix before its*, then the longest key.exportMatchesnow breaks that last tie as Node.js does (PATTERN_KEY_COMPARE), where it used to keep the object's order, and its*now stands for at least one character. A.jsxtarget counts as there when the.tsxfile TypeScript reads for it is. Anything else is still only called unchecked:dist,build,lib,out,esm,cjs), whatever its extension, built or not ("./*": { "types": "./dist/components/*.d.ts", "default": "./dist/components/*.js" }, or"./*": "./dist/*.tsx"), whose source may be any file the build reads (src/components/tooltip.ts);nulltarget;config.importsis only used to find the package's folder. Its targets cannot decide this, since they mapdist/back tosrc/*.tsx. The folder is the nearestpackage.jsonwith a name, so a nested{"type": "module"}insrc/componentsis passed over.src/explain.ts: newunpublishedComponents(ds), one message for an app that takes on the config of an installed package and knows no component from it:@acme/ui publishes neither its component sources nor their type declarations, so its components are unknown here and the component rules did not run: ask its team to add its sources to "files" in its package.json, or to publish type declarations.When the package does publish declarations and"libraries": falsein the config turned them off, it says that instead, and that"libraries": []reads them and no library. It adds a line about the token rules when there are tokens, then the docs link.inspect --explainprints it.src/server/render.tsandsrc/server/index.ts:list_componentsandget_componentuse that message.noComponentsMessagetakes the reason as an optional fourth argument.renderNotFounddropsAvailable: .when the list is empty.src/init.ts:ONSYSTEM.mdis added tofilesnext to the config, unlessfilesleaves it out ("!ONSYSTEM.md"), which is the team's call. The note names only the files it added.docs/design-system-packages.mddocuments all of the above. It also says that a config with"extends": falseand copied paths does not read the package'sexports. In a workspace app, such a config leaves an invented subpath import unchecked rather than reported.docs/rules.mdnames the theme-partial case next to Tailwind's defaults.Patch changeset.
Three existing tests assert on what changed:
test/design-system-package.test.tsandtest/init-registry-apps.test.ts: thefileslist and the init note;test/design-system-packages-docs.test.ts: the published files, thelist_componentsandget_componenttext, and the invented<Badge>in the subpath layout, which the package's config now reports.How it was tested
test/package-mode.test.tshas 31 tests. Run against main'ssrc/, 13 fail and 18 pass:p-[13px]is reported, both installed and as a workspace package;@tailwindcss/postcsscounts as v4 next to atailwindcss^3 range (3 tests)<Tooltip>from the missing subpath isno-unknown-component, while<StarIcon>, whose own export leads to an unbuiltdist/, is still only unchecked; the same past a nestedpackage.jsonwith no name; with"./*": "./src/components/*.jsx",<Tip>fromsrc/components/tip.tsxis unchecked and the invented<Popover>is reported (3 tests)list_componentsandget_componentgive the unpublished-sources message, and the"libraries": falseone when that turned the declarations off (2 tests)renderNotFoundwith an empty list no longer printsAvailable: .inspect --explainprints the messageinitputsONSYSTEM.mdinfiles, names only the files it added, and leavesONSYSTEM.mdout under"!ONSYSTEM.md"(3 tests)The 18 that pass on main are guards:
^3.4.0,~3.4.17,3.x), or when the partial clears the spacing namespace (5 tests);<Tooltip>from@acme/ui/tooltip, through"./*"intodist/componentswith its source insrc/components/tooltip.ts, is only unchecked, built or not, linked intonode_modulesor not (4 tests). The first version of this branch reported it in all 4.<Tip>from@acme/ui/components/tip.js, with"./components/*"intosrc/components/*.tsxand"./components/*.js"into a builtdist/components, in either order, and the same with"./*"and"./*.js", is only unchecked, linked or not (8 tests). In the linked tests, Node.js resolves the import todist/components/tip.js(createRequire(...).resolve);import.meta.resolvegives the same for all four orders. The previous version of this branch reported it in the 4 where the shorter key comes first."./components/*": "./dist/components/*.tsx"leaves<Popover>unchecked, which the previous version reported.I also ran the built CLI on the reviewer's subpath layouts: the shadcn/ui monorepo template with variants of its
exports, each with and without a pnpm-style link and withinit's config. On the 8dist-starlayouts withinit's config, the first version of this branch reported"Tooltip" is not a design-system component, and this one says it is unchecked. The other layouts give the same results as the first version, except the 4 with asourcecondition before adist/one: the invented<Tooltip>there is unchecked again, as on main. The pattern-order fix changes none of these 44 results. In the reviewer's Tailwind v3 app on a v4 partial,inspectshows 7 tokens, down from 12 on the first version, and none of v4's defaults.Gate, all passing:
pnpm install --frozen-lockfile --prefer-offlinepnpm format:checkpnpm lintpnpm typecheckpnpm test: 105 files passed, 1 skipped; 1355 tests passed, 3 skippedpnpm build:schema.jsonunchangedpnpm smoke: passedpnpm corpus: "Counts match corpus/snapshot.json." No snapshot change, so the README rate is untouched. The blind sample fp-sample-20261016 still has 80 of its 80 labels reported.Follow-ups (outside this PR's files)
check's notice in a dist-only app (notice()insrc/design-system.ts, open in fix(server): retry failed loads, reload JS configs, answer per path when --root holds projects #242) should useunpublishedComponents.plugins/onsystem/hooks/check-ui.mjs) should drop itsget_componenthint when there are no components.runsTailwindV4reads only the app's ownpackage.json: atailwindcsshoisted to the monorepo root is not seen, and acatalog:orworkspace:*range counts as v4, since it does not say. Reading the root'spackage.json, the pnpm catalog or the installed package would settle it."./*"leads into a builtdist/componentsreports<Tooltip>as unknown when its source is not in the components glob. Main does the same.node_modules/.pnpm/...) printed through thenode_modules/<name>link, ininspectand--explain(src/cli.ts,src/detect.ts,src/config.ts).initas package specifiers (@acme/tailwind-config/theme.css) and resolved in installed apps (src/config.ts).initalready warns about../token paths on main.corpus/repos.json).