@usequeek/theme-check 0.3.2 → 0.3.5

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/index.d.ts CHANGED
@@ -11,3 +11,5 @@ export { BUSINESS_KEYS, SERVICE_SLUGS, CATALOGUE, SUBCATEGORIES, isBusinessKey,
11
11
  export { TEMPLATE_COPY_PLACES, copyViolations, isTestimonialSection, storeNameForms } from './utils/template-copy.js';
12
12
  export { PRIMARY_DEMO_ID, DEMO_ID_FORMAT, demoFilesOf } from './utils/theme-demos.js';
13
13
  export { TEMPLATE_DESCRIPTION_MAX, screenshotFile, sectionStyle, sectionCopy, declaredFieldsByVariant } from './utils/theme-templates.js';
14
+ export { STATIC_RULES, moduleContractRule, structureRule, demoStoreRule, demoStoresRule, demoArtRule, codeQualityRule, sdkBoundaryRule, selectionMetadataRule, demoCompletenessRule, subscribeScopeRule, demoBlockTypesRule, identityRule, productMetafieldsRule, poweredByRule, fontsSelfHostedRule, templateDescriptionRule, templateScreenshotRule, templateChromeRule, templateStyleRule, templateBusinessRule, templateVersionsRule, templatePagesRule, templateCopyRule, vendorFactsRule, placeholderContentRule, frameworkImport, STARTER_PLACEHOLDER_IMAGES, } from './rules/static.js';
15
+ export { ANALYSIS_RULES, variantParityRule, fieldParityRule, designTokensRule } from './rules/analysis.js';
package/dist/index.js CHANGED
@@ -10,3 +10,8 @@ export { BUSINESS_KEYS, SERVICE_SLUGS, CATALOGUE, SUBCATEGORIES, isBusinessKey,
10
10
  export { TEMPLATE_COPY_PLACES, copyViolations, isTestimonialSection, storeNameForms } from './utils/template-copy.js';
11
11
  export { PRIMARY_DEMO_ID, DEMO_ID_FORMAT, demoFilesOf } from './utils/theme-demos.js';
12
12
  export { TEMPLATE_DESCRIPTION_MAX, screenshotFile, sectionStyle, sectionCopy, declaredFieldsByVariant } from './utils/theme-templates.js';
13
+ // Per-kind rule arrays and the individual rule constants, for rule-level unit
14
+ // tests that want to run one rule against a hand-built ThemeContext instead
15
+ // of a whole theme directory through checkTheme().
16
+ export { STATIC_RULES, moduleContractRule, structureRule, demoStoreRule, demoStoresRule, demoArtRule, codeQualityRule, sdkBoundaryRule, selectionMetadataRule, demoCompletenessRule, subscribeScopeRule, demoBlockTypesRule, identityRule, productMetafieldsRule, poweredByRule, fontsSelfHostedRule, templateDescriptionRule, templateScreenshotRule, templateChromeRule, templateStyleRule, templateBusinessRule, templateVersionsRule, templatePagesRule, templateCopyRule, vendorFactsRule, placeholderContentRule, frameworkImport, STARTER_PLACEHOLDER_IMAGES, } from './rules/static.js';
17
+ export { ANALYSIS_RULES, variantParityRule, fieldParityRule, designTokensRule } from './rules/analysis.js';
@@ -7,6 +7,10 @@ import { copyViolations, isTestimonialSection } from '../utils/template-copy.js'
7
7
  import { BUSINESS_KEYS, SERVICE_SLUGS, isBusinessKey } from '../utils/business-vocabulary.js';
8
8
  import { themeSourceFiles } from '../context.js';
9
9
  import { finding } from '../types.js';
10
+ /** A theme file as a finding names it: relative to the theme, with `/` on every OS (Windows gave `styles\type.css`). */
11
+ function themePath(context, path) {
12
+ return relative(context.dir, path).replace(/\\/g, '/');
13
+ }
10
14
  const REQUIRED_FILES = [
11
15
  'index.ts', 'manifest.ts', 'theme.config.ts',
12
16
  'layout.tsx', 'header.tsx', 'footer.tsx',
@@ -250,7 +254,7 @@ export const codeQualityRule = {
250
254
  // mention in a docblock, and three themes do.
251
255
  if (path.endsWith('.tsx') && /<img[\s>]/.test(stripComments(source))) {
252
256
  findings.push(finding(context, 'theme/code-quality', 'reject', {
253
- where: relative(context.dir, path),
257
+ where: themePath(context, path),
254
258
  found: 'renders a raw <img>',
255
259
  fix: "Use <Image /> from @usequeek/theme-kit/components/image. It carries the broken-image fallback, the Smart Placeholder for empty slots, and the srcset the backend ships as image_variants — a raw <img> silently gives up all three.",
256
260
  docs: `${context.env.docs}#what-themes-must-not-do`,
@@ -259,7 +263,7 @@ export const codeQualityRule = {
259
263
  const match = source.match(/from '(?:@\/)?themes\/(?!.*\/)?([\w-]+)/);
260
264
  if (match && match[1] !== context.slug) {
261
265
  findings.push(finding(context, 'theme/code-quality', 'reject', {
262
- where: relative(context.dir, path),
266
+ where: themePath(context, path),
263
267
  found: `imports from the "${match[1]}" theme`,
264
268
  fix: 'A theme is self-contained. Copy what you need into your own folder, or ask for it to be promoted into @usequeek/theme-kit if every theme needs it.',
265
269
  docs: `${context.env.docs}#what-themes-must-not-do`,
@@ -286,7 +290,7 @@ export const sdkBoundaryRule = {
286
290
  const findings = [];
287
291
  for (const path of themeSourceFiles(context.dir)) {
288
292
  const source = readFileSync(path, 'utf8');
289
- const where = relative(context.dir, path);
293
+ const where = themePath(context, path);
290
294
  if (/from '@queekai\/client-sdk'|from '@\/lib\/core\/sdk\//.test(source)) {
291
295
  findings.push(finding(context, 'theme/core-boundary', 'reject', {
292
296
  where,
@@ -1138,7 +1142,7 @@ export const vendorFactsRule = {
1138
1142
  for (const path of themeSourceFiles(context.dir)) {
1139
1143
  for (const { fact, words } of vendorFactFallbacks(readFileSync(path, 'utf8'))) {
1140
1144
  findings.push(finding(context, 'theme/vendor-facts', 'reject', {
1141
- where: relative(context.dir, path),
1145
+ where: themePath(context, path),
1142
1146
  found: `vendor.${fact} falls back to "${words}"`,
1143
1147
  fix: `A store with no ${fact} would show these words as its own. Render nothing when it is empty (\`vendor.${fact} ?? ''\`, or leave the element out).`,
1144
1148
  docs: `${context.env.docs}#component-rules`,
@@ -1159,7 +1163,7 @@ function themeCssFiles(dir) {
1159
1163
  }
1160
1164
  export const fontsSelfHostedRule = {
1161
1165
  id: 'theme/fonts-self-hosted',
1162
- summary: 'Theme fonts ship as files in the theme: next/font/google is rejected (it fails builds), a Google Fonts @import is flagged',
1166
+ summary: 'Theme fonts ship as files in the theme: next/font/google (fails builds) and a Google Fonts @import (dropped or render-blocking) are rejected',
1163
1167
  kind: 'static',
1164
1168
  run(context) {
1165
1169
  const findings = [];
@@ -1168,7 +1172,7 @@ export const fontsSelfHostedRule = {
1168
1172
  const source = stripComments(readFileSync(path, 'utf8'));
1169
1173
  if (/from\s+['"]next\/font\/google['"]/.test(source)) {
1170
1174
  findings.push(finding(context, 'theme/fonts-self-hosted', 'reject', {
1171
- where: relative(context.dir, path),
1175
+ where: themePath(context, path),
1172
1176
  found: 'imports next/font/google',
1173
1177
  fix,
1174
1178
  docs: `${context.env.docs}#fonts`,
@@ -1178,10 +1182,10 @@ export const fontsSelfHostedRule = {
1178
1182
  for (const path of themeCssFiles(context.dir)) {
1179
1183
  const css = readFileSync(path, 'utf8').replace(/\/\*[\s\S]*?\*\//g, '');
1180
1184
  if (/@import\s+(?:url\()?['"]?https?:\/\/fonts\.googleapis\.com/.test(css)) {
1181
- findings.push(finding(context, 'theme/fonts-self-hosted', 'warn', {
1182
- where: relative(context.dir, path),
1185
+ findings.push(finding(context, 'theme/fonts-self-hosted', 'reject', {
1186
+ where: themePath(context, path),
1183
1187
  found: 'loads a font with @import from fonts.googleapis.com',
1184
- fix: `Either the bundler drops it (it only survives as the very first rule of the compiled stylesheet), so the font never loads, or it survives and every page load waits on an extra render-blocking request to Google before the text can paint. ${fix}`,
1188
+ fix: `Either the bundler drops it (it only survives as the very first rule of the compiled stylesheet), so the font never loads — atelier, deluxr and lumiere shipped that way until 24/9/26 — or it survives and every page load waits on an extra render-blocking request to Google before the text can paint. ${fix}`,
1185
1189
  docs: `${context.env.docs}#fonts`,
1186
1190
  }));
1187
1191
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usequeek/theme-check",
3
- "version": "0.3.2",
3
+ "version": "0.3.5",
4
4
  "description": "The rules a Queek storefront theme is checked against, as a library.",
5
5
  "license": "MIT",
6
6
  "type": "module",