@vectoriox/iox-ui 5.58.0 → 5.59.0

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.
@@ -93,6 +93,7 @@ declare const SPEC_SITE_PLAN_SHAPE: {
93
93
  readonly "required?": "boolean — a template page the wizard's Pages step cannot leave out";
94
94
  readonly "inNav?": "boolean — a Link in the header and footer navigation, in plan order";
95
95
  readonly "archetype?": "string — site.archetypes: the kind of page; its sections must fill its required slots from the families it allows";
96
+ readonly "need?": "string — site.needIds (= harness.needs): the inferred need this page answers — the Plan screen tags it \"we added\"";
96
97
  readonly "template?": "string — the content type a template page renders one item of";
97
98
  readonly "routeSource?": "string — the single source read by the route param (route.* binds it)";
98
99
  readonly "seo?": "pageSeo";
@@ -152,6 +153,7 @@ declare const SPEC_SITE_DENSITY_COPY: {
152
153
  readonly regular: "standard";
153
154
  readonly airy: "standard";
154
155
  };
156
+ declare const SPEC_SITE_NEED_IDS: readonly ["collection", "detail", "services", "prices", "menu", "visit", "team", "about", "faq", "blog", "gallery", "booking-request", "sign-up-form", "contact"];
155
157
  declare const SPEC_SITE_ARCHETYPES: {
156
158
  readonly home: {
157
159
  readonly label: "Home";
@@ -4445,6 +4447,9 @@ interface PageArchetype {
4445
4447
  readonly slots: ReadonlyArray<PageArchetypeSlot>;
4446
4448
  }
4447
4449
  declare const PAGE_ARCHETYPES: Readonly<Record<string, PageArchetype>>;
4450
+ /** What a business may need (contract `site.needIds`, derived from the harness's ONE list — harness-core `NEEDS`). */
4451
+ type SiteNeedId = (typeof SPEC_SITE_NEED_IDS)[number];
4452
+ declare const SITE_NEED_IDS: ReadonlyArray<SiteNeedId>;
4448
4453
  interface PagePlan {
4449
4454
  readonly key: string;
4450
4455
  readonly name: string;
@@ -4460,6 +4465,8 @@ interface PagePlan {
4460
4465
  readonly routeSource?: string;
4461
4466
  /** The kind of page (`PAGE_ARCHETYPES`): its sections fill the type's required slots from the families it allows. */
4462
4467
  readonly archetype?: PageArchetypeId;
4468
+ /** The inferred need this page answers (the Plan screen tags it "we added") — a harness-core need id. */
4469
+ readonly need?: SiteNeedId;
4463
4470
  readonly seo?: PageSeoPlan;
4464
4471
  readonly sections: ReadonlyArray<PageSectionPlan>;
4465
4472
  }
@@ -5079,6 +5086,8 @@ declare enum SitePlanIssueCode {
5079
5086
  InvalidLocale = "invalid-locale",
5080
5087
  /** A page's SEO words are longer than a search result shows (seo-core limits). */
5081
5088
  InvalidSeo = "invalid-seo",
5089
+ /** A page names a need the harness does not have. */
5090
+ UnknownNeed = "unknown-need",
5082
5091
  /** A page key that is a global slot's name (`header`, `footer`): its sections' ids would be the global's. */
5083
5092
  ReservedPageKey = "reserved-page-key"
5084
5093
  }
@@ -6130,6 +6139,9 @@ interface WrittenText {
6130
6139
  }
6131
6140
  /** Every text in a plan a model writes (never ids, routes, field names or pattern ids). */
6132
6141
  declare function writtenTexts(plan: SitePlan): WrittenText[];
6142
+ /** Hebrew joins up to two one-letter words (and, the, in, to, from, that, as) to the next: "והטוב" holds "טוב". The
6143
+ * ONE rule — the intake's keyword match (harness-core) uses it too. */
6144
+ declare const HEBREW_PREFIXES = "[\u05D5\u05D4\u05D1\u05DC\u05DE\u05E9\u05DB]{0,2}";
6133
6145
  /** A word (or phrase) as a whole-word pattern; Hebrew allows its one-letter prefixes. */
6134
6146
  declare function wordPattern(word: string): RegExp;
6135
6147
  /** The words to avoid and the facts never given, in every written text of the plan. */
@@ -6365,5 +6377,5 @@ declare function addStockCredits(footer: SerializedNode, credits: ReadonlyArray<
6365
6377
  url: string;
6366
6378
  }>): number;
6367
6379
 
6368
- export { ACTIVE_BUILD_STATUSES, AI_REFUSAL_NEXT, AI_REFUSAL_STATUS, AI_STEPS, AI_STEP_LABELS, AI_STEP_NEEDS, AI_STEP_TYPICAL_TOKENS, AiCallStatus, AiCapability, AiFeature, AiGenerationStage, AiKeyMode, AiLimit, AiNextKind, AiProviderId, AiRefusalCode, AiStep, BAR_ITEMS_MAX, BAR_ITEMS_MIN, BASELINE_ROLES, BUILD_STEPS, BaselineRole, BindScope, BuildNoticeCode, BuildStep, CONTENT_ROLE_MEANINGS, CREDITS_PER_USD, CardBindTarget, CheckSeverity, ComposeError, ComposeIssueCode, ContentRole, ContentTypeAction, CreatedKind, DANGLING_LINK_CODES, DEFAULT_PHONE_MENU_BREAKPOINT, DEFAULT_SITE_LOCALE, ENTRANCE_EASING, ENTRANCE_ORIGIN_LOOK, ENTRANCE_TRIGGER, EntrancePart, EntranceSide, FACT_KEYS, FINAL_GENERATION_STAGES, FINDING_SEVERITY, GlobalSlot, JSON_SCHEMA_BANNED_KEYWORDS, JsonSchemaShapeError, KeptReason, NAV_PART_LABELS, NAV_SHAPE_COPY, NEUTRAL_STYLE_PROPS, NODE_BASELINES, NO_TOKENS, NavPagesSource, NavRole, NavShape, NavShapeError, PAGE_ARCHETYPES, PLAN_EDITS_ANSWER_SHAPE, PLAN_EDITS_SCHEMA_NAME, PLAN_EDIT_SHAPE, PRICING_PATTERN, PUBLISH_BLOCKING_PLACEHOLDERS, PageDataKind, PathIssueCollector, PatternDirective, PatternGlobalPosition, PatternOpens, PatternPlaceholder, PatternRecipe, PhoneMenuBreakpoint, PlaceholderKind, PlanChangeAction, PlanChangeKind, PlanDataSourceMode, PlanDataSourceType, PlanEditIssueCode, PlanEditOp, PlanEditsOutcome, PlanWordIssueCode, PreflightRefusalCode, PublishRefusalCode, REQUIRED_CONTENT_ROLES, RelativeOp, SAMPLE_IMAGE_REF, SITE_CHECKS, SITE_FACT_LABELS, SITE_HEADER_PATTERN, SITE_LIBRARY, SITE_LOCALES, SITE_PATTERNS, SITE_PLAN_SCHEMA_NAME, SITE_PLAN_VERSION, SITE_TEMPLATES, SPEC_SITE_ARCHETYPES, SPEC_SITE_COPY_LENGTHS, SPEC_SITE_DENSITY_COPY, SPEC_SITE_FACTS, SPEC_SITE_LIBRARY, SPEC_SITE_LOCALES, SPEC_SITE_PATTERNS, SPEC_SITE_PLAN_SHAPE, SPEC_SITE_REQUIRED_ROLES, SPEC_SITE_ROLES, SPEC_SITE_TEMPLATES, STOCK_FAMILIES, STUDIO_TEMPLATE, SiteBuildKind, SiteBuildStatus, SiteCheckId, SiteFindingCode, SiteLocale, SitePlanError, SitePlanIssueCode, SitePlanSourceKind, SitePlanWireKey, SiteTemplateError, SiteTemplateId, StepState, StockProviderId, addBarItem, addStockCredits, applyPlanEdits, applyStockPhotos, archetypeIssues, assertStyleSlots, assertValidSitePlan, auditSite, barIconForRoute, blocksPublish, buildKeys, buildStepFacts, builtHomePageId, composeNavHeader, composeSection, composeSite, contentTypeFromWire, contentTypeJsonSchema, contentTypePreviewFields, copyLengthOf, costUsd, createSerializedNode, creditsOfUsd, dataSourceJsonSchema, describePlanData, describeShapeKey, entranceAction, entranceInteraction, estimateStepCredits, failedBuildStep, fieldJsonSchema, findNavRoot, isActiveBuild, isNonEmptyString, isPlainObject, isRtlLocale, jsonAnyOf, jsonBoolean, jsonClosedObject, jsonInteger, jsonListOf, jsonOneOf, jsonSchemaKeywords, jsonSchemaObjects, jsonShapedObject, jsonText, modelCanDo, moveBarItem, navPages, navShapeBreakpoint, navShapeOf, nextSourceOf, nodeBindPaths, pageJsonSchema, parsePatternPath, parseSampleImageRef, pathAt, patternById, patternHasForm, patternLinkSlots, patternManifest, patternNeedsBinding, patternNodes, patternOptionalParts, patternRoleNeeds, patternScopes, patternSlotBudgets, patternSlots, patternTakesBinding, phoneMenuPages, planEditsFromWire, planEditsJsonSchema, planEntrances, planFromTemplate, planNavShape, planStockPhotos, planWordIssues, publishRefusal, publishVerdict, releasedLayoutDefaults, removeBarItem, requiredAcknowledgements, requiredShapeKeys, roleField, routeMatches, routeParams, sampleImageRef, sectionEntrances, sectionFromWire, sectionJsonSchema, sectionPatternIds, setStyleProps, shapeKeys, showcaseGlobals, showcasePages, showcasePlans, siteNavPages, sitePlanFromWire, sitePlanJsonSchema, sitePlanToWire, slotBudget, stockCopyKey, stockCreditLines, stockCreditNode, stockCreditNodeId, stockSlots, validatePlanEdits, validateSitePlan, walkSerialized, wordPattern, writtenTexts };
6369
- export type { AddBarItemResult, AiEntitlementsView, AiMeter, AiModelEntry, AiRefusal, AiTokenCounts, AiTokenPrice, AuditPage, AuditPlaceholder, BarItemsEditResult, BuildNotice, BuildStepError, BuildStepFacts, BuildStepRecord, CmsDataSourcePlan, ComposeContext, ComposeIssue, ComposedDataSource, ComposedItem, ComposedNavHeader, ComposedPage, ComposedPlaceholder, ComposedRoute, ComposedSection, ComposedSite, ContentFieldPlan, ContentRoles, ContentSeedPlan, ContentTypePlan, CreateNodeOptions, CreatedRecord, DataSourcePlan, DynamicKeysAsList, EntranceAction, EntranceActionOptions, EntranceInteraction, EntranceMark, EntranceSpec, EntranceStamp, FactKey, JsonSchema, NavHeaderInput, NavHeaderOptions, NavPage, NavShapeOptions, NavShapeResult, NodeBaseline, PageArchetype, PageArchetypeId, PageArchetypeSlot, PageData, PageDataLine, PagePlan, PageSectionPlan, PageSeoPlan, PathIssue, PatternManifestEntry, PatternNode, PatternPath, PatternRoleNeed, PlainObject, PlanChange, PlanEdit, PlanEditIssue, PlanEditResult, PlanEditsAnswer, PlanEntrancesInput, PlanWordContext, PlanWordIssue, PreflightRefusal, PublishRefusal, RelativeDataSourcePlan, SectionEntrances, SectionInput, SectionOptions, SerializedBinding, SerializedNode, SerializedResponsive, ShapeEntry, ShapeIssueCodes, ShowcaseInput, SiteAudit, SiteAuditOptions, SiteAuditSnapshot, SiteBuildRun, SiteBusiness, SiteCheck, SiteFinding, SitePageRef, SitePattern, SitePlan, SitePlanIssue, SitePlanSchemaPin, SitePlanSource, SitePlanValidation, SiteTemplate, StockCredit, StockPhoto, StockPlacement, StockSlot, TemplatePlanInput, UndoKept, UndoPreview, UndoRecord, WrittenText };
6380
+ export { ACTIVE_BUILD_STATUSES, AI_REFUSAL_NEXT, AI_REFUSAL_STATUS, AI_STEPS, AI_STEP_LABELS, AI_STEP_NEEDS, AI_STEP_TYPICAL_TOKENS, AiCallStatus, AiCapability, AiFeature, AiGenerationStage, AiKeyMode, AiLimit, AiNextKind, AiProviderId, AiRefusalCode, AiStep, BAR_ITEMS_MAX, BAR_ITEMS_MIN, BASELINE_ROLES, BUILD_STEPS, BaselineRole, BindScope, BuildNoticeCode, BuildStep, CONTENT_ROLE_MEANINGS, CREDITS_PER_USD, CardBindTarget, CheckSeverity, ComposeError, ComposeIssueCode, ContentRole, ContentTypeAction, CreatedKind, DANGLING_LINK_CODES, DEFAULT_PHONE_MENU_BREAKPOINT, DEFAULT_SITE_LOCALE, ENTRANCE_EASING, ENTRANCE_ORIGIN_LOOK, ENTRANCE_TRIGGER, EntrancePart, EntranceSide, FACT_KEYS, FINAL_GENERATION_STAGES, FINDING_SEVERITY, GlobalSlot, HEBREW_PREFIXES, JSON_SCHEMA_BANNED_KEYWORDS, JsonSchemaShapeError, KeptReason, NAV_PART_LABELS, NAV_SHAPE_COPY, NEUTRAL_STYLE_PROPS, NODE_BASELINES, NO_TOKENS, NavPagesSource, NavRole, NavShape, NavShapeError, PAGE_ARCHETYPES, PLAN_EDITS_ANSWER_SHAPE, PLAN_EDITS_SCHEMA_NAME, PLAN_EDIT_SHAPE, PRICING_PATTERN, PUBLISH_BLOCKING_PLACEHOLDERS, PageDataKind, PathIssueCollector, PatternDirective, PatternGlobalPosition, PatternOpens, PatternPlaceholder, PatternRecipe, PhoneMenuBreakpoint, PlaceholderKind, PlanChangeAction, PlanChangeKind, PlanDataSourceMode, PlanDataSourceType, PlanEditIssueCode, PlanEditOp, PlanEditsOutcome, PlanWordIssueCode, PreflightRefusalCode, PublishRefusalCode, REQUIRED_CONTENT_ROLES, RelativeOp, SAMPLE_IMAGE_REF, SITE_CHECKS, SITE_FACT_LABELS, SITE_HEADER_PATTERN, SITE_LIBRARY, SITE_LOCALES, SITE_NEED_IDS, SITE_PATTERNS, SITE_PLAN_SCHEMA_NAME, SITE_PLAN_VERSION, SITE_TEMPLATES, SPEC_SITE_ARCHETYPES, SPEC_SITE_COPY_LENGTHS, SPEC_SITE_DENSITY_COPY, SPEC_SITE_FACTS, SPEC_SITE_LIBRARY, SPEC_SITE_LOCALES, SPEC_SITE_NEED_IDS, SPEC_SITE_PATTERNS, SPEC_SITE_PLAN_SHAPE, SPEC_SITE_REQUIRED_ROLES, SPEC_SITE_ROLES, SPEC_SITE_TEMPLATES, STOCK_FAMILIES, STUDIO_TEMPLATE, SiteBuildKind, SiteBuildStatus, SiteCheckId, SiteFindingCode, SiteLocale, SitePlanError, SitePlanIssueCode, SitePlanSourceKind, SitePlanWireKey, SiteTemplateError, SiteTemplateId, StepState, StockProviderId, addBarItem, addStockCredits, applyPlanEdits, applyStockPhotos, archetypeIssues, assertStyleSlots, assertValidSitePlan, auditSite, barIconForRoute, blocksPublish, buildKeys, buildStepFacts, builtHomePageId, composeNavHeader, composeSection, composeSite, contentTypeFromWire, contentTypeJsonSchema, contentTypePreviewFields, copyLengthOf, costUsd, createSerializedNode, creditsOfUsd, dataSourceJsonSchema, describePlanData, describeShapeKey, entranceAction, entranceInteraction, estimateStepCredits, failedBuildStep, fieldJsonSchema, findNavRoot, isActiveBuild, isNonEmptyString, isPlainObject, isRtlLocale, jsonAnyOf, jsonBoolean, jsonClosedObject, jsonInteger, jsonListOf, jsonOneOf, jsonSchemaKeywords, jsonSchemaObjects, jsonShapedObject, jsonText, modelCanDo, moveBarItem, navPages, navShapeBreakpoint, navShapeOf, nextSourceOf, nodeBindPaths, pageJsonSchema, parsePatternPath, parseSampleImageRef, pathAt, patternById, patternHasForm, patternLinkSlots, patternManifest, patternNeedsBinding, patternNodes, patternOptionalParts, patternRoleNeeds, patternScopes, patternSlotBudgets, patternSlots, patternTakesBinding, phoneMenuPages, planEditsFromWire, planEditsJsonSchema, planEntrances, planFromTemplate, planNavShape, planStockPhotos, planWordIssues, publishRefusal, publishVerdict, releasedLayoutDefaults, removeBarItem, requiredAcknowledgements, requiredShapeKeys, roleField, routeMatches, routeParams, sampleImageRef, sectionEntrances, sectionFromWire, sectionJsonSchema, sectionPatternIds, setStyleProps, shapeKeys, showcaseGlobals, showcasePages, showcasePlans, siteNavPages, sitePlanFromWire, sitePlanJsonSchema, sitePlanToWire, slotBudget, stockCopyKey, stockCreditLines, stockCreditNode, stockCreditNodeId, stockSlots, validatePlanEdits, validateSitePlan, walkSerialized, wordPattern, writtenTexts };
6381
+ export type { AddBarItemResult, AiEntitlementsView, AiMeter, AiModelEntry, AiRefusal, AiTokenCounts, AiTokenPrice, AuditPage, AuditPlaceholder, BarItemsEditResult, BuildNotice, BuildStepError, BuildStepFacts, BuildStepRecord, CmsDataSourcePlan, ComposeContext, ComposeIssue, ComposedDataSource, ComposedItem, ComposedNavHeader, ComposedPage, ComposedPlaceholder, ComposedRoute, ComposedSection, ComposedSite, ContentFieldPlan, ContentRoles, ContentSeedPlan, ContentTypePlan, CreateNodeOptions, CreatedRecord, DataSourcePlan, DynamicKeysAsList, EntranceAction, EntranceActionOptions, EntranceInteraction, EntranceMark, EntranceSpec, EntranceStamp, FactKey, JsonSchema, NavHeaderInput, NavHeaderOptions, NavPage, NavShapeOptions, NavShapeResult, NodeBaseline, PageArchetype, PageArchetypeId, PageArchetypeSlot, PageData, PageDataLine, PagePlan, PageSectionPlan, PageSeoPlan, PathIssue, PatternManifestEntry, PatternNode, PatternPath, PatternRoleNeed, PlainObject, PlanChange, PlanEdit, PlanEditIssue, PlanEditResult, PlanEditsAnswer, PlanEntrancesInput, PlanWordContext, PlanWordIssue, PreflightRefusal, PublishRefusal, RelativeDataSourcePlan, SectionEntrances, SectionInput, SectionOptions, SerializedBinding, SerializedNode, SerializedResponsive, ShapeEntry, ShapeIssueCodes, ShowcaseInput, SiteAudit, SiteAuditOptions, SiteAuditSnapshot, SiteBuildRun, SiteBusiness, SiteCheck, SiteFinding, SiteNeedId, SitePageRef, SitePattern, SitePlan, SitePlanIssue, SitePlanSchemaPin, SitePlanSource, SitePlanValidation, SiteTemplate, StockCredit, StockPhoto, StockPlacement, StockSlot, TemplatePlanInput, UndoKept, UndoPreview, UndoRecord, WrittenText };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vectoriox/iox-ui",
3
- "version": "5.58.0",
3
+ "version": "5.59.0",
4
4
  "peerDependencies": {
5
5
  "@angular/common": ">=20.0.0",
6
6
  "@angular/core": ">=20.0.0",
@@ -54,8 +54,9 @@ export function writtenTexts(plan: SitePlan): WrittenText[] {
54
54
  }
55
55
 
56
56
  const HEBREW = /[֐-׿]/;
57
- /** Hebrew joins up to two one-letter words (and, the, in, to, from, that, as) to the next: "והטוב" holds "טוב". */
58
- const HEBREW_PREFIXES = '[והבלמשכ]{0,2}';
57
+ /** Hebrew joins up to two one-letter words (and, the, in, to, from, that, as) to the next: "והטוב" holds "טוב". The
58
+ * ONE rule — the intake's keyword match (harness-core) uses it too. */
59
+ export const HEBREW_PREFIXES = '[והבלמשכ]{0,2}';
59
60
  const escape = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
60
61
  const normalise = (s: string) => s.normalize('NFKC').toLowerCase();
61
62
 
@@ -8,7 +8,7 @@ import {
8
8
  patternHasForm, patternLinkSlots, patternOptionalParts, patternSlots, patternTakesBinding, PatternGlobalPosition, SITE_PATTERNS, SitePattern,
9
9
  } from './patterns';
10
10
  import {
11
- FACT_KEYS, GlobalSlot, PAGE_ARCHETYPES, PlanDataSourceMode, PlanDataSourceType, RelativeOp, SitePlan, SitePlanSource, SitePlanSourceKind, SITE_LOCALES,
11
+ FACT_KEYS, GlobalSlot, PAGE_ARCHETYPES, SITE_NEED_IDS, PlanDataSourceMode, PlanDataSourceType, RelativeOp, SitePlan, SitePlanSource, SitePlanSourceKind, SITE_LOCALES,
12
12
  SITE_PLAN_VERSION,
13
13
  } from './site-plan.model';
14
14
  import { SPEC_SITE_PLAN_SHAPE } from './site-spec.generated';
@@ -151,7 +151,7 @@ export function pageJsonSchema(): JsonSchema {
151
151
  const seo = jsonShapedObject(SHAPE['pageSeo'], { title: jsonText(), description: jsonText() }, 'pageSeo');
152
152
  return jsonShapedObject(SHAPE['page'], {
153
153
  key: jsonText(), name: jsonText(), route: jsonText(), isHome: jsonBoolean(), required: jsonBoolean(), inNav: jsonBoolean(),
154
- archetype: jsonOneOf(Object.keys(PAGE_ARCHETYPES)), template: jsonText(), routeSource: jsonText(), seo, sections: jsonListOf(sectionJsonSchema()),
154
+ archetype: jsonOneOf(Object.keys(PAGE_ARCHETYPES)), need: jsonOneOf(SITE_NEED_IDS), template: jsonText(), routeSource: jsonText(), seo, sections: jsonListOf(sectionJsonSchema()),
155
155
  }, 'page');
156
156
  }
157
157
 
@@ -1,6 +1,6 @@
1
1
  import type { AnimateId, DesignChoices } from '@vectoriox/iox-ui/design-core';
2
2
 
3
- import { SPEC_SITE_ARCHETYPES, SPEC_SITE_FACTS, SPEC_SITE_LOCALES, SPEC_SITE_REQUIRED_ROLES, SPEC_SITE_ROLES } from './site-spec.generated';
3
+ import { SPEC_SITE_ARCHETYPES, SPEC_SITE_FACTS, SPEC_SITE_LOCALES, SPEC_SITE_NEED_IDS, SPEC_SITE_REQUIRED_ROLES, SPEC_SITE_ROLES } from './site-spec.generated';
4
4
 
5
5
  /**
6
6
  * The Site Plan (contract `site.planShape`, `SPEC_SITE_PLAN_SHAPE`: every key typed and explained, and the
@@ -157,6 +157,10 @@ export interface PageArchetype {
157
157
  }
158
158
  export const PAGE_ARCHETYPES: Readonly<Record<string, PageArchetype>> = SPEC_SITE_ARCHETYPES;
159
159
 
160
+ /** What a business may need (contract `site.needIds`, derived from the harness's ONE list — harness-core `NEEDS`). */
161
+ export type SiteNeedId = (typeof SPEC_SITE_NEED_IDS)[number];
162
+ export const SITE_NEED_IDS: ReadonlyArray<SiteNeedId> = SPEC_SITE_NEED_IDS;
163
+
160
164
  export interface PagePlan {
161
165
  readonly key: string;
162
166
  readonly name: string;
@@ -172,6 +176,8 @@ export interface PagePlan {
172
176
  readonly routeSource?: string;
173
177
  /** The kind of page (`PAGE_ARCHETYPES`): its sections fill the type's required slots from the families it allows. */
174
178
  readonly archetype?: PageArchetypeId;
179
+ /** The inferred need this page answers (the Plan screen tags it "we added") — a harness-core need id. */
180
+ readonly need?: SiteNeedId;
175
181
  readonly seo?: PageSeoPlan;
176
182
  readonly sections: ReadonlyArray<PageSectionPlan>;
177
183
  }
@@ -94,6 +94,7 @@ export const SPEC_SITE_PLAN_SHAPE = {
94
94
  "required?": "boolean — a template page the wizard's Pages step cannot leave out",
95
95
  "inNav?": "boolean — a Link in the header and footer navigation, in plan order",
96
96
  "archetype?": "string — site.archetypes: the kind of page; its sections must fill its required slots from the families it allows",
97
+ "need?": "string — site.needIds (= harness.needs): the inferred need this page answers — the Plan screen tags it \"we added\"",
97
98
  "template?": "string — the content type a template page renders one item of",
98
99
  "routeSource?": "string — the single source read by the route param (route.* binds it)",
99
100
  "seo?": "pageSeo",
@@ -162,6 +163,23 @@ export const SPEC_SITE_DENSITY_COPY = {
162
163
  "airy": "standard"
163
164
  } as const;
164
165
 
166
+ export const SPEC_SITE_NEED_IDS = [
167
+ "collection",
168
+ "detail",
169
+ "services",
170
+ "prices",
171
+ "menu",
172
+ "visit",
173
+ "team",
174
+ "about",
175
+ "faq",
176
+ "blog",
177
+ "gallery",
178
+ "booking-request",
179
+ "sign-up-form",
180
+ "contact"
181
+ ] as const;
182
+
165
183
  export const SPEC_SITE_ARCHETYPES = {
166
184
  "home": {
167
185
  "label": "Home",
@@ -7,7 +7,7 @@ import {
7
7
  patternSlots, PatternGlobalPosition, slotBudget,
8
8
  } from './patterns';
9
9
  import {
10
- FACT_KEYS, GlobalSlot, PAGE_ARCHETYPES, PlanDataSourceMode, PlanDataSourceType, RelativeOp, REQUIRED_CONTENT_ROLES, SitePlan, SitePlanSourceKind,
10
+ FACT_KEYS, GlobalSlot, PAGE_ARCHETYPES, SITE_NEED_IDS, PlanDataSourceMode, PlanDataSourceType, RelativeOp, REQUIRED_CONTENT_ROLES, SitePlan, SitePlanSourceKind,
11
11
  SITE_LOCALES, SITE_PLAN_VERSION,
12
12
  } from './site-plan.model';
13
13
  import { SPEC_SITE_PLAN_SHAPE } from './site-spec.generated';
@@ -65,6 +65,8 @@ export enum SitePlanIssueCode {
65
65
  InvalidLocale = 'invalid-locale',
66
66
  /** A page's SEO words are longer than a search result shows (seo-core limits). */
67
67
  InvalidSeo = 'invalid-seo',
68
+ /** A page names a need the harness does not have. */
69
+ UnknownNeed = 'unknown-need',
68
70
  /** A page key that is a global slot's name (`header`, `footer`): its sections' ids would be the global's. */
69
71
  ReservedPageKey = 'reserved-page-key',
70
72
  }
@@ -335,6 +337,8 @@ function validatePages(c: Collector, list: unknown[], types: Map<string, Content
335
337
  const archetype = c.string(raw, 'archetype', path, false);
336
338
  if (archetype && !has(PAGE_ARCHETYPES, archetype)) c.add(SitePlanIssueCode.Archetype, `${path}.archetype`, `"${archetype}" is not a page type (${Object.keys(PAGE_ARCHETYPES).join(', ')})`);
337
339
  validatePageSeo(c, raw['seo'], `${path}.seo`);
340
+ const need = c.string(raw, 'need', path, false);
341
+ if (need && !(SITE_NEED_IDS as ReadonlyArray<string>).includes(need)) c.add(SitePlanIssueCode.UnknownNeed, `${path}.need`, `"${need}" is not a need (${SITE_NEED_IDS.join(', ')})`);
338
342
 
339
343
  c.array(raw, 'sections', path).forEach((s, j) => {
340
344
  const sp = `${path}.sections[${j}]`;
@@ -1,3 +1,5 @@
1
+ import { HEBREW_PREFIXES } from '@vectoriox/iox-ui/generation-core';
2
+
1
3
  import { BUSINESS_TYPES, BusinessType } from './business-types';
2
4
 
3
5
  /**
@@ -7,9 +9,6 @@ import { BUSINESS_TYPES, BusinessType } from './business-types';
7
9
  * the reading stage (M1-1) checks the model against the same match.
8
10
  */
9
11
 
10
- /** A single Hebrew letter that prefixes a word (the, in, to, and, from, that, as) — "בסדנאות" holds "סדנ". */
11
- const HEBREW_PREFIX = '[הבלומשכ]?';
12
-
13
12
  const escapeRe = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
14
13
 
15
14
  const KEYWORD_RES = new Map<string, RegExp>();
@@ -18,7 +17,7 @@ const KEYWORD_RES = new Map<string, RegExp>();
18
17
  function keywordRe(keyword: string): RegExp {
19
18
  let re = KEYWORD_RES.get(keyword);
20
19
  if (!re) {
21
- re = new RegExp(`(^|[^\\p{L}\\p{N}])${HEBREW_PREFIX}${escapeRe(keyword.toLocaleLowerCase())}`, 'u');
20
+ re = new RegExp(`(^|[^\\p{L}\\p{N}])${HEBREW_PREFIXES}${escapeRe(keyword.toLocaleLowerCase())}`, 'u');
22
21
  KEYWORD_RES.set(keyword, re);
23
22
  }
24
23
  return re;