@wix/origami-lint 1.34.10 → 1.34.12

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.
Files changed (23) hide show
  1. package/dist/page-model/index.js +1 -1
  2. package/dist/rules/index.js +16 -16
  3. package/dist/rules/project/home-page-folder.js +54 -0
  4. package/dist/rules/project/index.js +2 -1
  5. package/dist/rules/rule-base.js +2 -0
  6. package/dist/rules/{allowed-imports.js → site-app/allowed-imports.js} +3 -3
  7. package/dist/rules/{apply-and-presets.js → site-app/apply-and-presets.js} +1 -1
  8. package/dist/rules/{bindings.js → site-app/bindings.js} +1 -1
  9. package/dist/rules/{breakpoints.js → site-app/breakpoints.js} +1 -1
  10. package/dist/rules/{css-file-nesting.js → site-app/css-file-nesting.js} +1 -1
  11. package/dist/rules/{css-layout-properties.js → site-app/css-layout-properties.js} +1 -1
  12. package/dist/rules/{css-selectors.js → site-app/css-selectors.js} +1 -1
  13. package/dist/rules/{data-values.js → site-app/data-values.js} +1 -1
  14. package/dist/rules/{global-styles.js → site-app/global-styles.js} +1 -1
  15. package/dist/rules/{no-absolute-section.js → site-app/no-absolute-section.js} +1 -1
  16. package/dist/rules/{no-free-code.js → site-app/no-free-code.js} +1 -1
  17. package/dist/rules/{page-structure.js → site-app/page-structure.js} +2 -2
  18. package/dist/rules/{slot-attributes.js → site-app/slot-attributes.js} +1 -1
  19. package/dist/rules/{theme-font-ids.js → site-app/theme-font-ids.js} +1 -1
  20. package/dist/rules/{theme-root.js → site-app/theme-root.js} +1 -1
  21. package/dist/shared/site-files-tree-mapping.js +2 -0
  22. package/package.json +2 -2
  23. /package/dist/rules/{define-rule.js → site-app/define-rule.js} +0 -0
@@ -1,5 +1,5 @@
1
1
  // Part 2 — page model: which pages to lint, and one page's model (its components, each with its CSS).
2
2
  export * from "./model.js";
3
3
  export { buildPageModel } from "./build-page-model.js";
4
- export { findPagesToLint, JSX_FILES } from "./pages.js";
4
+ export { findPages, findPagesToLint, JSX_FILES } from "./pages.js";
5
5
  export { readPage } from "./read-page.js";
@@ -1,17 +1,17 @@
1
- import allowedImports from "./allowed-imports.js";
2
- import applyAndPresets from "./apply-and-presets.js";
3
- import bindings from "./bindings.js";
4
- import breakpoints from "./breakpoints.js";
5
- import cssFileNesting from "./css-file-nesting.js";
6
- import cssLayoutProperties from "./css-layout-properties.js";
7
- import cssSelectors from "./css-selectors.js";
8
- import dataValues from "./data-values.js";
9
- import globalStyles from "./global-styles.js";
10
- import noAbsoluteSection from "./no-absolute-section.js";
11
- import pageStructure from "./page-structure.js";
12
- import slotAttributes from "./slot-attributes.js";
13
- import themeFontIds from "./theme-font-ids.js";
14
- import themeRoot from "./theme-root.js";
15
- import noFreeCode from "./no-free-code.js";
1
+ import allowedImports from "./site-app/allowed-imports.js";
2
+ import applyAndPresets from "./site-app/apply-and-presets.js";
3
+ import bindings from "./site-app/bindings.js";
4
+ import breakpoints from "./site-app/breakpoints.js";
5
+ import cssFileNesting from "./site-app/css-file-nesting.js";
6
+ import cssLayoutProperties from "./site-app/css-layout-properties.js";
7
+ import cssSelectors from "./site-app/css-selectors.js";
8
+ import dataValues from "./site-app/data-values.js";
9
+ import globalStyles from "./site-app/global-styles.js";
10
+ import noAbsoluteSection from "./site-app/no-absolute-section.js";
11
+ import pageStructure from "./site-app/page-structure.js";
12
+ import slotAttributes from "./site-app/slot-attributes.js";
13
+ import themeFontIds from "./site-app/theme-font-ids.js";
14
+ import themeRoot from "./site-app/theme-root.js";
15
+ import noFreeCode from "./site-app/no-free-code.js";
16
16
  export const ruleRegistry = [allowedImports, noFreeCode, pageStructure, noAbsoluteSection, themeFontIds, slotAttributes, themeRoot, breakpoints, cssFileNesting, globalStyles, applyAndPresets, bindings, dataValues, cssLayoutProperties, cssSelectors];
17
- export { defineRule } from "./define-rule.js";
17
+ export { defineRule } from "./site-app/define-rule.js";
@@ -0,0 +1,54 @@
1
+ // The home page folder (tracker OUR-035, CONV-unitPath.ts:89): exactly one folder in parentheses, pages/(<slug>), directly
2
+ // under pages/, and no other folder in parentheses in pages/ or popups/. `origami import-site` stops without exactly one
3
+ // home folder and refuses a nested one; the converter refuses a popup folder in parentheses.
4
+ import { findPages } from "../../page-model/index.js";
5
+ import { PAGES_FOLDER, POPUPS_FOLDER } from "../../shared/site-files-tree-mapping.js";
6
+ import { defineProjectRule } from "./define-project-rule.js";
7
+ const EXPECTED_ONE_HOME = `Expected exactly one home page folder "pages/(<slug>)" in ${PAGES_FOLDER}`;
8
+ export const NO_HOME = `${EXPECTED_ONE_HOME}; found 0. Name the home page's folder in parentheses, directly under ${PAGES_FOLDER}, like ${PAGES_FOLDER}/(home) (rule P2-R01; tracker OUR-035). The import stops without it.`;
9
+ export const moreHomes = (count, folder) => `${EXPECTED_ONE_HOME}; found ${count}. Keep the parentheses on the home page's folder only: rename ${folder} to ${withoutParentheses(folder)} (rule P2-R01; tracker OUR-035).`;
10
+ export const onlyHomeInParentheses = (folder) => `Only the home page is written in parentheses, directly under ${PAGES_FOLDER}/. Rename ${folder} to ${withoutParentheses(folder)} (rule P2-R23; tracker CONV-unitPath.ts:89).`;
11
+ /** A home page's folder: its name in parentheses, `(home)`. */
12
+ const HOME_FOLDER = /^\(.+\)$/;
13
+ export default defineProjectRule({
14
+ name: 'home-page-folder',
15
+ editors: ['studio2'],
16
+ check: (project) => [...checkOneHome(project), ...checkNoNestedHome(project), ...checkNoPopupInParentheses(project)],
17
+ });
18
+ // ── the steps ──
19
+ /** Reports no home folder at the top of pages/, or more than one (each after the first). */
20
+ function checkOneHome(project) {
21
+ const homes = getPages(project).filter((page) => page.folders.length === 1 && HOME_FOLDER.test(page.folders[0]));
22
+ if (homes.length === 0)
23
+ return [{ file: PAGES_FOLDER, message: NO_HOME }];
24
+ return homes.slice(1).map((home) => ({ file: home.jsxFile, message: moreHomes(homes.length, home.folders[0]) }));
25
+ }
26
+ /** Reports every page with a folder in parentheses below the top of pages/ on its path, as import-site refuses them. */
27
+ function checkNoNestedHome(project) {
28
+ return getPages(project).flatMap((page) => {
29
+ const nested = page.folders.slice(1).find((folder) => HOME_FOLDER.test(folder));
30
+ return nested ? [{ file: page.jsxFile, message: onlyHomeInParentheses(nested) }] : [];
31
+ });
32
+ }
33
+ /** Reports each folder in parentheses under popups/, once, as the converter refuses them. */
34
+ function checkNoPopupInParentheses(project) {
35
+ const folders = new Set();
36
+ for (const file of project.files.filter((file) => file.startsWith(`${POPUPS_FOLDER}/`))) {
37
+ const segments = file.slice(`${POPUPS_FOLDER}/`.length).split('/').slice(0, -1);
38
+ const index = segments.findIndex((segment) => HOME_FOLDER.test(segment));
39
+ if (index !== -1)
40
+ folders.add(`${POPUPS_FOLDER}/${segments.slice(0, index + 1).join('/')}`);
41
+ }
42
+ return [...folders].sort().map((folder) => ({ file: folder, message: onlyHomeInParentheses(folder.slice(folder.lastIndexOf('/') + 1)) }));
43
+ }
44
+ /** The site's pages under pages/, sorted by path. */
45
+ function getPages(project) {
46
+ return findPages([...project.files], [...project.files])
47
+ .filter((jsxFile) => jsxFile.startsWith(`${PAGES_FOLDER}/`))
48
+ .sort()
49
+ .map((jsxFile) => ({ jsxFile, folders: jsxFile.slice(`${PAGES_FOLDER}/`.length).split('/').slice(0, -1) }));
50
+ }
51
+ /** '(team)' → 'team'. */
52
+ function withoutParentheses(folder) {
53
+ return folder.slice(1, -1);
54
+ }
@@ -1,2 +1,3 @@
1
+ import homePageFolder from "./home-page-folder.js";
1
2
  export { defineProjectRule } from "./define-project-rule.js";
2
- export const projectRuleRegistry = [];
3
+ export const projectRuleRegistry = [homePageFolder];
@@ -0,0 +1,2 @@
1
+ // What every rule has, whatever it runs on: a page rule (`Rule`, in site-app/) or a project rule (`ProjectRule`, in project/).
2
+ export {};
@@ -2,9 +2,9 @@
2
2
  // converter 0.80 a page's interactions live in servicesConfigs/interactions.ts, and structure.jsx can't use these packages (0.86
3
3
  // refuses a tag from them, parseJsx.ts:471, identity.ts:80; a call is free code, and fn() / ctx() refuse them as a source).
4
4
  import path from 'node:path';
5
- import { CSS_FILES, JSX_FILES } from "../page-model/index.js";
6
- import { BUILDERS, RUNTIME_ONLY_BUILDERS, RUNTIME_PACKAGE } from "../rules-api/index.js";
7
- import { GLOBAL_COMPONENTS, GLOBAL_COMPONENTS_FOLDER, GLOBAL_FOLDER, SITE_SRC } from "../shared/site-files-tree-mapping.js";
5
+ import { CSS_FILES, JSX_FILES } from "../../page-model/index.js";
6
+ import { BUILDERS, RUNTIME_ONLY_BUILDERS, RUNTIME_PACKAGE } from "../../rules-api/index.js";
7
+ import { GLOBAL_COMPONENTS, GLOBAL_COMPONENTS_FOLDER, GLOBAL_FOLDER, SITE_SRC } from "../../shared/site-files-tree-mapping.js";
8
8
  import { defineRule } from "./define-rule.js";
9
9
  /** The interactions packages, which the import reserves: structure.jsx imports nothing from them. Matched by source, not by name: `Interact` from @site/site-code is the site's own. */
10
10
  const INTERACTIONS_PACKAGES = ['interactReact', 'interact', 'motionPresets'];
@@ -1,4 +1,4 @@
1
- import { createCssFileReporter, describeAtRule, getCssChildren, getDashedId, getSegmentClass, getSelectorSegments, isPresetProperty, isSafeCssIdentifier } from "../rules-api/index.js";
1
+ import { createCssFileReporter, describeAtRule, getCssChildren, getDashedId, getSegmentClass, getSelectorSegments, isPresetProperty, isSafeCssIdentifier } from "../../rules-api/index.js";
2
2
  import { defineRule } from "./define-rule.js";
3
3
  export default defineRule({
4
4
  name: 'apply-and-presets',
@@ -1,4 +1,4 @@
1
- import { BUILDERS, CALLBACK_PROP, EVENT_ATTRIBUTE, RESERVED_ENTRY_KEYS, RUNTIME_PACKAGE, TRANSFORM_BUILDERS, TYPED_BUILDERS, bare, getAttribute, getExpression, getKey, getCallbackKind, getName, getObject, getParamReadKind, getProperties, getProperty, isBound, isReservedAttribute, isStructure, ownerOf, } from "../rules-api/index.js";
1
+ import { BUILDERS, CALLBACK_PROP, EVENT_ATTRIBUTE, RESERVED_ENTRY_KEYS, RUNTIME_PACKAGE, TRANSFORM_BUILDERS, TYPED_BUILDERS, bare, getAttribute, getExpression, getKey, getCallbackKind, getName, getObject, getParamReadKind, getProperties, getProperty, isBound, isReservedAttribute, isStructure, ownerOf, } from "../../rules-api/index.js";
2
2
  import { defineRule } from "./define-rule.js";
3
3
  /** The converter's reserved sources (identity.ts `isReservedRegistry`) and the DM's own `document`: no fn()/ctx() names. */
4
4
  const RESERVED_FOR_BINDINGS = ['runtime', 'interactReact', 'interact', 'motionPresets', 'menu', 'document', 'core'];
@@ -1,4 +1,4 @@
1
- import { describeAtRule, reportCssProblem } from "../rules-api/index.js";
1
+ import { describeAtRule, reportCssProblem } from "../../rules-api/index.js";
2
2
  import { defineRule } from "./define-rule.js";
3
3
  /** The converter's shape for a declaration's name: a dashed identifier. */
4
4
  const DASHED_NAME = /^--[A-Za-z0-9_-]+$/;
@@ -1,4 +1,4 @@
1
- import { BREAKPOINT_AT_RULES, createCssFileReporter, describeAtRule, getCssChildren, ORIGAMI_TARGETS, PREAMBLE_LAYER } from "../rules-api/index.js";
1
+ import { BREAKPOINT_AT_RULES, createCssFileReporter, describeAtRule, getCssChildren, ORIGAMI_TARGETS, PREAMBLE_LAYER } from "../../rules-api/index.js";
2
2
  import { defineRule } from "./define-rule.js";
3
3
  /** The import's leading-import line (cssFileParser.ts `IMPORT_LINE_PATTERN`). */
4
4
  const IMPORT_LINE = /^@import '([^']+)';$/;
@@ -1,4 +1,4 @@
1
- import { CONTENT_TARGET, createCssFileReporter, getName, LAYER_ATTRIBUTES, OVERFLOW_TARGET } from "../rules-api/index.js";
1
+ import { CONTENT_TARGET, createCssFileReporter, getName, LAYER_ATTRIBUTES, OVERFLOW_TARGET } from "../../rules-api/index.js";
2
2
  import { defineRule } from "./define-rule.js";
3
3
  // ── the tables (propSpecs.ts) ──
4
4
  const keywords = (...values) => ({ values, allowed: values.join(', ') });
@@ -1,4 +1,4 @@
1
- import { BREAKPOINT_AT_RULES, createCssFileReporter, getSelectorSegments, isCssIdentifier, isSafeCssIdentifier, PREAMBLE_LAYER, readSegment } from "../rules-api/index.js";
1
+ import { BREAKPOINT_AT_RULES, createCssFileReporter, getSelectorSegments, isCssIdentifier, isSafeCssIdentifier, PREAMBLE_LAYER, readSegment } from "../../rules-api/index.js";
2
2
  import { defineRule } from "./define-rule.js";
3
3
  /** The at-rules whose rules the import reads: breakpoint blocks, and a `@mixin`'s `@result`. */
4
4
  const READ_AT_RULES = [...BREAKPOINT_AT_RULES, 'result'];
@@ -2,7 +2,7 @@
2
2
  // 1227, 1231, 1235, 1255, 1268, 1289, 1697; projectData.ts 214, 225, 281, 435, 443; enrichImage.ts 94, 105.
3
3
  // Converter 0.81 (checked at 0.84, 2c0e21c): the tag's import, not a `type` attr, decides if a component takes data attributes; `type` is data.
4
4
  import { isDeepStrictEqual } from 'node:util';
5
- import { DATA_KEY, EVENT_ATTRIBUTE, RESERVED_ATTRIBUTES, RESERVED_ENTRY_KEYS, bare, getAttribute, getExpression, getKey, getName, getObject, getProperties, getCallbackKind, getProperty, isBound, isOneEditAway, isReservedAttribute, isStructure, ownerOf, } from "../rules-api/index.js";
5
+ import { DATA_KEY, EVENT_ATTRIBUTE, RESERVED_ATTRIBUTES, RESERVED_ENTRY_KEYS, bare, getAttribute, getExpression, getKey, getName, getObject, getProperties, getCallbackKind, getProperty, isBound, isOneEditAway, isReservedAttribute, isStructure, ownerOf, } from "../../rules-api/index.js";
6
6
  import { defineRule } from "./define-rule.js";
7
7
  /** The names the import never reads as data (dataKeys.ts). The React name is joined as the converter does: Wix Standards fails the build on it in any file. */
8
8
  const EXCLUDED_DATA_KEYS = [
@@ -1,4 +1,4 @@
1
- import { BREAKPOINT_AT_RULES, createCssFileReporter, describeAtRule, getCssChildren, getDashedId, getSegmentClass, getSelectorSegments, isCssIdentifier, isSafeCssIdentifier } from "../rules-api/index.js";
1
+ import { BREAKPOINT_AT_RULES, createCssFileReporter, describeAtRule, getCssChildren, getDashedId, getSegmentClass, getSelectorSegments, isCssIdentifier, isSafeCssIdentifier } from "../../rules-api/index.js";
2
2
  import { defineRule } from "./define-rule.js";
3
3
  export default defineRule({
4
4
  name: 'global-styles',
@@ -1,4 +1,4 @@
1
- import { SECTIONS } from "../rules-api/index.js";
1
+ import { SECTIONS } from "../../rules-api/index.js";
2
2
  import { defineRule } from "./define-rule.js";
3
3
  export default defineRule({
4
4
  name: 'no-absolute-section',
@@ -1,4 +1,4 @@
1
- import { STRUCTURE } from "../rules-api/index.js";
1
+ import { STRUCTURE } from "../../rules-api/index.js";
2
2
  import { defineRule } from "./define-rule.js";
3
3
  const FREE_CODE = 'The import refuses this statement: a structure file holds only imports, `const` / `let` / `var` declarations and `export const Structure = () => …` (tracker CONV-parseJsx.ts:287).';
4
4
  const STRUCTURE_SHAPE = 'Declare Structure once, as `export const Structure = () => ( <Page …/> )`: an exported const arrow that returns the root element directly, with no `{ return … }`, fragment or condition around it (tracker CONV-parseJsx.ts:335).';
@@ -19,8 +19,8 @@
19
19
  // <Interaction> is no wrapper since converter 0.80 (interactions live in servicesConfigs/interactions.ts): allowed-imports
20
20
  // reports the tag, and it stays transparent here so the elements inside it aren't reported too. Context-provider wrappers join
21
21
  // once the page model lists the providers.
22
- import { FILE_START } from "../page-model/index.js";
23
- import { LAYER_ATTRIBUTES, SECTIONS, WRAPPERS } from "../rules-api/index.js";
22
+ import { FILE_START } from "../../page-model/index.js";
23
+ import { LAYER_ATTRIBUTES, SECTIONS, WRAPPERS } from "../../rules-api/index.js";
24
24
  import { defineRule } from "./define-rule.js";
25
25
  export default defineRule({
26
26
  name: 'page-structure',
@@ -5,7 +5,7 @@
5
5
  // - the root element has no `slot=`: it has no owner to be a slot of (CONV-fromBundle.ts:1312);
6
6
  // - two children of one owner don't share a slot key (CONV-slots.ts:555).
7
7
  // Children are the element children and the layer elements (backgroundLayer, pinnedLayer); <Remove> and <Interaction> are transparent.
8
- import { LAYER_ATTRIBUTES, WRAPPERS } from "../rules-api/index.js";
8
+ import { LAYER_ATTRIBUTES, WRAPPERS } from "../../rules-api/index.js";
9
9
  import { defineRule } from "./define-rule.js";
10
10
  export default defineRule({
11
11
  name: 'slot-attributes',
@@ -5,7 +5,7 @@
5
5
  // theme.css isn't a file oxlint lints, so the rule runs on each linted page (a theme change lints every page) and
6
6
  // marks the page's start; the message names the token's line in theme.css.
7
7
  import { fonts } from '@wix/origami-fonts';
8
- import { reportCssProblem } from "../rules-api/index.js";
8
+ import { reportCssProblem } from "../../rules-api/index.js";
9
9
  import { defineRule } from "./define-rule.js";
10
10
  const FONT_TOKEN = /^--wst-[\w-]+-font$/;
11
11
  // The size in a `font` shorthand, with its optional line height: the family follows it. The number's quantifiers
@@ -1,4 +1,4 @@
1
- import { describeAtRule, isPresetProperty, PREAMBLE_LAYER, reportCssProblem } from "../rules-api/index.js";
1
+ import { describeAtRule, isPresetProperty, PREAMBLE_LAYER, reportCssProblem } from "../../rules-api/index.js";
2
2
  import { defineRule } from "./define-rule.js";
3
3
  const SPX_PROPS = ['--spx-ref-width', '--spx-resolver-type'];
4
4
  const SPX_RESOLVERS = ['scale', 'fixed'];
@@ -2,6 +2,8 @@
2
2
  export const SITE_SRC = 'packages/site-app/src';
3
3
  /** One page per folder; routes can be nested (about-us/team). */
4
4
  export const PAGES_FOLDER = `${SITE_SRC}/pages`;
5
+ /** One popup per folder, directly under it (popups have no url, so no nesting). */
6
+ export const POPUPS_FOLDER = `${SITE_SRC}/popups`;
5
7
  /** What every page shares: the global components, the menus, the theme. */
6
8
  export const GLOBAL_FOLDER = `${SITE_SRC}/global`;
7
9
  /** Inside src/: one global component per folder (the header, the footer, any other shared section). A page imports one from here. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/origami-lint",
3
- "version": "1.34.10",
3
+ "version": "1.34.12",
4
4
  "description": "Offline lint for an exported Origami site: lints the pages that changed since the last passing run",
5
5
  "type": "module",
6
6
  "bin": {
@@ -52,5 +52,5 @@
52
52
  ]
53
53
  }
54
54
  },
55
- "falconPackageHash": "df5ca3b838244854a52ae4013469c645c6bd6d3e1651ee3702545903"
55
+ "falconPackageHash": "c50f6ccef419b969c9a223c3355e8bf3623b41236d615b837ffd5283"
56
56
  }