@warpgogol/werkstatt-shared 0.14.0 → 0.15.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.
- package/README.md +31 -13
- package/README.uk.md +25 -15
- package/package.json +519 -762
- package/src/{share/agent → agent}/ard-catalog.ts +6 -1
- package/src/{share/agent → agent}/dns-aid.test.ts +2 -2
- package/src/{share/agent → agent}/manifest.ts +15 -1
- package/src/{share/agent → agent}/search.ts +6 -1
- package/src/{share → agent}/tests/api-catalog.test.ts +2 -2
- package/src/{share → agent}/tests/ard-catalog.test.ts +2 -2
- package/src/{share → agent}/tests/capability.test.ts +1 -1
- package/src/{share → agent}/tests/fleet-catalog.test.ts +1 -1
- package/src/{share → agent}/tests/knowledge.test.ts +2 -2
- package/src/{share → agent}/tests/manifest.test.ts +1 -1
- package/src/{share → agent}/tests/mcp-card.test.ts +2 -2
- package/src/agent/tests/omit-empty.test.ts +33 -0
- package/src/{share → agent}/tests/openapi.test.ts +2 -2
- package/src/{share → agent}/tests/proof.test.ts +1 -1
- package/src/{share → attribution}/material-credits.ts +4 -4
- package/src/{share → checks}/check-hints.ts +6 -1
- package/src/checks/index.ts +4 -1
- package/src/checks/lib/astro-site-url.ts +6 -1
- package/src/checks/lib/i18n.ts +14 -0
- package/src/checks/result-helpers.ts +22 -5
- package/src/checks/tests/remediation-auto-populate.test.ts +83 -0
- package/src/{share → client-scripts}/counter-utils.ts +6 -2
- package/src/{share/scripts → client-scripts}/external-link-qr.ts +11 -16
- package/src/{share/scripts → client-scripts}/external-links.ts +12 -1
- package/src/{share/scripts → client-scripts}/gsap-counter.ts +8 -3
- package/src/client-scripts/index.ts +35 -0
- package/src/{share/scripts → client-scripts}/inline-number-animation.ts +1 -1
- package/src/{share/scripts → client-scripts}/lenis.ts +6 -1
- package/src/{share/scripts → client-scripts}/lordicon.ts +6 -1
- package/src/{share/scripts → client-scripts}/orchestrator.ts +10 -1
- package/src/{share/scripts → client-scripts}/scheduler.ts +6 -1
- package/src/client-scripts/scroll-spy.ts +106 -0
- package/src/client-scripts/tests/external-link-qr.test.ts +8 -0
- package/src/client-scripts/tests/external-links.test.ts +25 -0
- package/src/client-scripts/tests/gsap-counter.test.ts +8 -0
- package/src/client-scripts/tests/gsap-mountain-journey.test.ts +8 -0
- package/src/client-scripts/tests/gsap-parallax.test.ts +8 -0
- package/src/client-scripts/tests/gsap-reveal.test.ts +8 -0
- package/src/client-scripts/tests/gsap-stagger.test.ts +8 -0
- package/src/client-scripts/tests/inline-number-animation.test.ts +8 -0
- package/src/client-scripts/tests/lenis.test.ts +8 -0
- package/src/client-scripts/tests/live-photos.test.ts +8 -0
- package/src/client-scripts/tests/lordicon.test.ts +8 -0
- package/src/client-scripts/tests/orchestrator.test.ts +47 -0
- package/src/client-scripts/tests/scheduler.test.ts +23 -0
- package/src/client-scripts/tests/scroll-spy.test.ts +204 -0
- package/src/{share/scripts → client-scripts/tests}/video-player.test.ts +51 -31
- package/src/component/contracts.ts +206 -0
- package/src/component/index.ts +11 -0
- package/src/{share → content}/content-reference.ts +3 -3
- package/src/{share/content → content}/entity-id.ts +6 -3
- package/src/content/index.ts +3 -0
- package/src/{share/content → content}/merge.ts +6 -1
- package/src/content/system-manifest.test.ts +107 -0
- package/src/content/system-manifest.ts +12 -94
- package/src/{share → content}/tests/resolve-field-path.test.ts +1 -1
- package/src/{share → content}/tests/substitute-deep.test.ts +1 -1
- package/src/content-discipline/index.ts +19 -0
- package/src/{share/content-discipline → content-discipline}/parsers.ts +2 -2
- package/src/{share/env.d.ts → env.d.ts} +6 -3
- package/src/fingerprint/canonical-json.ts +731 -0
- package/src/fingerprint/index.ts +12 -0
- package/src/fingerprint/primitives.ts +72 -0
- package/src/{share/i18n → i18n}/localization.ts +6 -2
- package/src/integration/adapters.ts +10 -71
- package/src/integration/dispatch.ts +1 -1
- package/src/integration/funnel.ts +6 -1
- package/src/integration/index.ts +101 -4
- package/src/integration/lagebild-destination-adapter.ts +108 -0
- package/src/integration/lagebild-ingress.ts +7 -12
- package/src/integration/orchestration.ts +11 -10
- package/src/integration/tests/deliver-event.test.ts +1 -1
- package/src/integration/tests/dispatch.test.ts +4 -4
- package/src/integration/tests/hub-runtime.test.ts +22 -14
- package/src/integration/vitest.config.ts +8 -0
- package/src/kernel/desired-state.ts +227 -0
- package/src/kernel/diagnostic.ts +289 -0
- package/src/kernel/fs-atomic.ts +131 -0
- package/src/kernel/index.ts +15 -0
- package/src/kernel/tests/fs-atomic.test.ts +150 -0
- package/src/kernel/tests/workspace-io.test.ts +187 -0
- package/src/kernel/types.ts +459 -0
- package/src/kernel/workspace-io.ts +248 -0
- package/src/{share → knowledge}/tests/claim.test.ts +1 -1
- package/src/{share → knowledge}/tests/derivation.test.ts +1 -1
- package/src/{share → knowledge}/tests/freshness.test.ts +1 -1
- package/src/{share → knowledge}/tests/ledger.test.ts +1 -1
- package/src/{share → knowledge}/tests/plan.test.ts +1 -1
- package/src/{share → knowledge}/tests/source.test.ts +1 -1
- package/src/legal/index.ts +15 -0
- package/src/{share/middleware → middleware}/access-protection.ts +8 -8
- package/src/{share → node}/dev-props-validator.ts +6 -1
- package/src/{share → node}/import-scan.ts +23 -3
- package/src/{share → node}/semantic/derived-prices-loader.ts +4 -2
- package/src/{share → node}/semantic/markdown-twin-provenance.ts +1 -1
- package/src/node/tests/derived-prices-loader.test.ts +59 -0
- package/src/node/tests/markdown-twin-provenance.test.ts +152 -0
- package/src/observability/env-resolver.ts +6 -1
- package/src/observability/index.ts +6 -1
- package/src/observability/otlp-converter.ts +6 -1
- package/src/observability/otlp-transport.ts +6 -1
- package/src/observability/pusher.ts +6 -1
- package/src/observability/redact.ts +6 -1
- package/src/observability/typed-refs.ts +6 -2
- package/src/observability/vitest.config.ts +1 -0
- package/src/{share → offers}/formula-eval.ts +3 -3
- package/src/{share → offers}/tests/formula-eval.test.ts +2 -2
- package/src/onboarding/index.ts +1 -0
- package/src/{share → onboarding}/tests/onboarding-yaml.test.ts +1 -1
- package/src/ontology/archetype-registry.ts +6 -1
- package/src/ontology/archetypes/index.json +33 -1
- package/src/ontology/archetypes/index.yaml +27 -1
- package/src/ontology/archetypes/sections/entity-grid.yaml +46 -0
- package/src/ontology/archetypes/sections/exit-diagram.yaml +43 -0
- package/src/ontology/biome-token-projection.ts +6 -1
- package/src/ontology/cosmic/index.ts +6 -1
- package/src/ontology/cosmic/moon-catalog.ts +6 -1
- package/src/ontology/cosmic/planet-catalog.ts +6 -1
- package/src/ontology/cosmic/star-catalog.ts +6 -1
- package/src/ontology/enums.ts +6 -1
- package/src/ontology/external-surfaces/index.ts +1 -1
- package/src/ontology/index.ts +6 -2
- package/src/ontology/manifest.ts +26 -4
- package/src/ontology/operations/artifact-store.ts +45 -0
- package/src/ontology/operations/dht.ts +98 -0
- package/src/ontology/operations/handoff.ts +92 -0
- package/src/ontology/operations/index.ts +187 -1
- package/src/ontology/operations/leitstand.ts +99 -0
- package/src/ontology/operations/materialization.ts +90 -0
- package/src/ontology/operations/mission.ts +111 -0
- package/src/ontology/operations/naming-policy.ts +132 -0
- package/src/ontology/operations/notausgang.ts +64 -0
- package/src/ontology/operations/release.ts +121 -0
- package/src/ontology/operations/sternsystem.ts +192 -0
- package/src/ontology/operations/werkstatt.ts +48 -0
- package/src/ontology/schemas/biome.ts +7 -2
- package/src/ontology/schemas/capability.ts +1 -1
- package/src/ontology/schemas/constellation.ts +6 -1
- package/src/ontology/schemas/index.ts +6 -2
- package/src/ontology/schemas/manifest-resolver.ts +6 -1
- package/src/ontology/schemas/page-entry.ts +9 -5
- package/src/ontology/schemas/system/growth.ts +6 -1
- package/src/ontology/schemas/system/manifest.ts +40 -1
- package/src/ontology/schemas/system/page-output.ts +7 -6
- package/src/ontology/schemas/system/tests/growth.test.ts +22 -0
- package/src/ontology/schemas/system/tests/integrations.test.ts +12 -0
- package/src/ontology/schemas/system/tests/manifest.test.ts +22 -0
- package/src/ontology/schemas/system/tests/page-output.test.ts +13 -0
- package/src/ontology/schemas/system/tests/release.test.ts +22 -0
- package/src/ontology/schemas/system/tests/text.test.ts +18 -0
- package/src/ontology/schemas/system/tests/verification.test.ts +12 -0
- package/src/ontology/schemas/system/text.ts +15 -0
- package/src/ontology/schemas/system.ts +6 -2
- package/src/ontology/schemas/tests/biome.test.ts +19 -0
- package/src/ontology/schemas/tests/capability.test.ts +22 -0
- package/src/ontology/schemas/tests/constellation.test.ts +22 -0
- package/src/ontology/schemas/tests/dns-records.test.ts +13 -0
- package/src/ontology/schemas/tests/manifest-resolver.test.ts +13 -0
- package/src/ontology/schemas/tests/page-entry.test.ts +22 -0
- package/src/ontology/schemas/tests/section-archetype.test.ts +12 -0
- package/src/ontology/schemas/tests/site-family.test.ts +18 -0
- package/src/ontology/schemas/tests/system.test.ts +20 -0
- package/src/ontology/shared-section-props/body-fragments.ts +2 -0
- package/src/ontology/tests/sternsystem-owner.test.ts +1 -1
- package/src/ontology/vitest.config.ts +1 -0
- package/src/{share → page}/page.ts +13 -9
- package/src/{share → page}/tests/dev-props-validator.test.ts +1 -1
- package/src/{share → page}/tests/hero-section-numbering-parity.test.ts +1 -1
- package/src/passport/index.ts +6 -1
- package/src/passport/key-rotate.ts +10 -2
- package/src/passport/schema.ts +6 -1
- package/src/passport/sign.ts +8 -3
- package/src/passport/vitest.config.ts +1 -0
- package/src/pbt/index.test.ts +95 -0
- package/src/pbt/index.ts +251 -0
- package/src/plugin/plugin-contract.ts +1 -1
- package/src/{share → policy}/entitlement.ts +24 -4
- package/src/{share → policy}/feature-policy.ts +8 -3
- package/src/{share → policy}/visibility.ts +7 -2
- package/src/redirects/redirects.ts +117 -0
- package/src/{share → redirects/tests}/redirects.test.ts +1 -1
- package/src/remediation/remediation-catalog.ts +316 -0
- package/src/{share/routes → routes}/template-filter.ts +1 -1
- package/src/{share → runtime}/runtime-context.ts +7 -2
- package/src/{share → runtime}/shared-context.ts +1 -1
- package/src/{share/schemas → schemas}/claims.ts +2 -2
- package/src/{share/schemas → schemas}/effects.ts +6 -1
- package/src/{share/schemas → schemas}/features.ts +1 -1
- package/src/{share/schemas → schemas}/index.ts +3 -3
- package/src/{share/schemas → schemas}/navigation.ts +6 -1
- package/src/{share/schemas → schemas}/page-base.ts +6 -2
- package/src/{share/schemas → schemas}/person.ts +1 -1
- package/src/{share/schemas → schemas}/standard-list-item.ts +1 -1
- package/src/schemas/tests/claim-records.test.ts +52 -0
- package/src/schemas/tests/claims.test.ts +23 -0
- package/src/schemas/tests/effects.test.ts +116 -0
- package/src/schemas/tests/features.test.ts +61 -0
- package/src/schemas/tests/horizontal-align.test.ts +16 -0
- package/src/schemas/tests/icon-color.test.ts +16 -0
- package/src/schemas/tests/live-photo.test.ts +40 -0
- package/src/schemas/tests/material-credit.test.ts +51 -0
- package/src/schemas/tests/media.test.ts +26 -0
- package/src/schemas/tests/navigation.test.ts +58 -0
- package/src/schemas/tests/page-base.test.ts +19 -0
- package/src/schemas/tests/participant.test.ts +26 -0
- package/src/schemas/tests/person.test.ts +12 -0
- package/src/schemas/tests/print.test.ts +30 -0
- package/src/schemas/tests/section-background.test.ts +31 -0
- package/src/schemas/tests/section-body.test.ts +16 -0
- package/src/schemas/tests/section-cards.test.ts +17 -0
- package/src/schemas/tests/section-cta.test.ts +41 -0
- package/src/schemas/tests/section-header.test.ts +31 -0
- package/src/schemas/tests/section-image.test.ts +24 -0
- package/src/schemas/tests/section-motion.test.ts +29 -0
- package/src/schemas/tests/section-shell.test.ts +42 -0
- package/src/schemas/tests/section-stats.test.ts +17 -0
- package/src/schemas/tests/site-background.test.ts +33 -0
- package/src/schemas/tests/standard-list-item.test.ts +16 -0
- package/src/{share → sections}/rfc0042-utils.ts +1 -1
- package/src/{share/semantic → semantic}/block-extractors/index.ts +20 -1
- package/src/{share/semantic → semantic}/business-projection.ts +95 -1
- package/src/semantic/canonical-uri.ts +54 -0
- package/src/{share/semantic → semantic}/extract.ts +100 -1
- package/src/semantic/fact-extraction.test.ts +47 -0
- package/src/semantic/fact-extraction.ts +46 -0
- package/src/semantic/freshness.ts +67 -0
- package/src/{share/semantic → semantic}/ids.ts +6 -1
- package/src/{share/semantic → semantic}/index.ts +9 -2
- package/src/{share/semantic → semantic}/jsonld/breadcrumb.ts +6 -2
- package/src/{share/semantic → semantic}/jsonld/context.ts +6 -2
- package/src/{share/semantic → semantic}/jsonld/faq.ts +6 -2
- package/src/{share/semantic → semantic}/jsonld/initiative.ts +6 -1
- package/src/{share/semantic → semantic}/jsonld/organization.ts +6 -1
- package/src/{share/semantic → semantic}/jsonld/person.ts +6 -2
- package/src/{share/semantic → semantic}/jsonld/service.ts +6 -2
- package/src/semantic/jsonld/shared.ts +36 -0
- package/src/semantic/jsonld/tests/article.test.ts +89 -0
- package/src/semantic/jsonld/tests/breadcrumb.test.ts +62 -0
- package/src/semantic/jsonld/tests/collection-list.test.ts +39 -0
- package/src/semantic/jsonld/tests/faq.test.ts +60 -0
- package/src/semantic/jsonld/tests/initiative.test.ts +56 -0
- package/src/semantic/jsonld/tests/organization.test.ts +123 -0
- package/src/semantic/jsonld/tests/person.test.ts +89 -0
- package/src/semantic/jsonld/tests/service.test.ts +65 -0
- package/src/semantic/jsonld/tests/shared.test.ts +41 -0
- package/src/semantic/jsonld/tests/video.test.ts +84 -0
- package/src/semantic/jsonld/tests/webpage.test.ts +93 -0
- package/src/semantic/jsonld/tests/website.test.ts +27 -0
- package/src/semantic/jsonld/types.ts +24 -0
- package/src/{share/semantic → semantic}/jsonld/webpage.ts +6 -1
- package/src/semantic/jsonld/website.ts +32 -0
- package/src/{share/semantic → semantic}/jsonld.ts +6 -1
- package/src/{share/semantic → semantic}/llms.ts +41 -3
- package/src/{share/semantic → semantic}/models.ts +27 -38
- package/src/{share/semantic → semantic}/organization-profile.ts +3 -0
- package/src/{share/semantic → semantic}/page-builders/markdown-page.ts +6 -3
- package/src/{share/semantic → semantic}/page-utils.ts +6 -3
- package/src/semantic/tests/ai.test.ts +55 -0
- package/src/semantic/tests/block-extraction.test.ts +34 -0
- package/src/{share/tests/breadcrumbs.test.ts → semantic/tests/breadcrumbs-0229.test.ts} +1 -1
- package/src/semantic/tests/breadcrumbs.test.ts +127 -0
- package/src/{share → semantic}/tests/build-page-price-markers.test.ts +2 -2
- package/src/semantic/tests/build-page.test.ts +122 -0
- package/src/semantic/tests/business-projection.test.ts +367 -0
- package/src/semantic/tests/canonical-uri.test.ts +56 -0
- package/src/semantic/tests/extract.test.ts +209 -0
- package/src/semantic/tests/feed.test.ts +113 -0
- package/src/semantic/tests/freshness.pbt.test.ts +108 -0
- package/src/semantic/tests/helpers.ts +32 -0
- package/src/semantic/tests/ids.test.ts +118 -0
- package/src/{share/tests/image-sitemap.test.ts → semantic/tests/image-sitemap-0150.test.ts} +1 -1
- package/src/semantic/tests/image-sitemap.test.ts +109 -0
- package/src/{share → semantic}/tests/jsonld-service.test.ts +2 -2
- package/src/{share → semantic}/tests/jsonld-video.test.ts +3 -3
- package/src/{share → semantic}/tests/jsonld-webpage.test.ts +3 -3
- package/src/semantic/tests/jsonld.test.ts +61 -0
- package/src/{share → semantic}/tests/llms-0789.test.ts +2 -2
- package/src/semantic/tests/llms-policy.test.ts +60 -0
- package/src/semantic/tests/llms.test.ts +164 -0
- package/src/semantic/tests/markdown-hygiene.test.ts +72 -0
- package/src/semantic/tests/markdown-page.test.ts +97 -0
- package/src/{share → semantic}/tests/organization-jsonld.test.ts +3 -3
- package/src/semantic/tests/organization-profile.test.ts +107 -0
- package/src/{share/tests/output-projection.test.ts → semantic/tests/output-projection-0143.test.ts} +1 -1
- package/src/semantic/tests/output-projection.test.ts +77 -0
- package/src/semantic/tests/page-markdown.test.ts +98 -0
- package/src/semantic/tests/page-utils.test.ts +88 -0
- package/src/{share/tests/price-marker-resolver.test.ts → semantic/tests/price-marker-resolver-0767.test.ts} +2 -2
- package/src/semantic/tests/price-marker-resolver.test.ts +90 -0
- package/src/semantic/tests/project-claims.pbt.test.ts +60 -0
- package/src/semantic/tests/robots.test.ts +70 -0
- package/src/{share/semantic → semantic}/tests/split-sentences.test.ts +1 -1
- package/src/{share → semantic}/tests/twin-path.test.ts +1 -1
- package/src/semantic/tests/update-stamp.test.ts +102 -0
- package/src/signing/index.ts +13 -0
- package/src/signing/key.ts +139 -0
- package/src/signing/sign.ts +66 -0
- package/src/signing/types.ts +29 -0
- package/src/{share/slug → slug}/slug-url.ts +4 -1
- package/src/stack/run-tool.ts +108 -0
- package/src/stack/stack-checks.ts +124 -0
- package/src/stack/tests/run-tool.test.ts +138 -0
- package/src/stack/tests/stack-checks.test.ts +141 -0
- package/src/stack/tests/walk-files.test.ts +131 -0
- package/src/stack/walk-files.ts +114 -0
- package/src/surface/blueprint.ts +342 -66
- package/src/surface/decision-composer.ts +6 -1
- package/src/surface/geo.ts +6 -1
- package/src/surface/index.ts +11 -7
- package/src/surface/types.ts +2 -2
- package/src/surface/vitest.config.ts +1 -0
- package/src/tests/signing-core.test.ts +129 -0
- package/src/{share → text}/css-value-normalize.ts +6 -1
- package/src/text/string-utils.ts +24 -0
- package/src/{share → text}/tests/text-normalize.test.ts +5 -0
- package/src/{share → text}/text-normalize.ts +4 -3
- package/src/{share → text}/wrap-inline-numbers.ts +1 -1
- package/src/types/axiom-study.d.ts +36 -0
- package/src/types/hls-js-light.d.ts +21 -0
- package/src/types/qrcode-browser.d.ts +23 -0
- package/src/typography/fix.pbt.test.ts +208 -0
- package/src/typography/fix.ts +148 -0
- package/src/typography/index.ts +54 -0
- package/src/typography/locale-defaults.ts +97 -0
- package/src/typography/rules-tier1.test.ts +459 -0
- package/src/typography/rules-tier1.ts +925 -0
- package/src/typography/rules-tier2-locale.pbt.test.ts +190 -0
- package/src/typography/rules-tier2-locale.test.ts +286 -0
- package/src/typography/rules-tier2-locale.ts +399 -0
- package/src/typography/rules-tier2-structure.test.ts +330 -0
- package/src/typography/rules-tier2-structure.ts +378 -0
- package/src/typography/rules-tier3-advisory.test.ts +290 -0
- package/src/typography/rules-tier3-advisory.ts +239 -0
- package/src/typography/text-surface.test.ts +244 -0
- package/src/typography/text-surface.ts +448 -0
- package/src/index.ts +0 -14
- package/src/integration/port-barrel.ts +0 -105
- package/src/share/content/index.ts +0 -16
- package/src/share/content-discipline/index.ts +0 -14
- package/src/share/index.ts +0 -86
- package/src/share/legal/index.ts +0 -1
- package/src/share/redirects.ts +0 -54
- package/src/share/scripts/index.ts +0 -26
- package/src/share/semantic/jsonld/shared.ts +0 -31
- package/src/share/semantic/jsonld/types.ts +0 -18
- package/src/share/semantic/jsonld/website.ts +0 -27
- package/src/share/string-utils.ts +0 -19
- package/src/share/types/axiom-study.d.ts +0 -22
- package/src/share/types/hls-js-light.d.ts +0 -16
- package/src/share/types/qrcode-browser.d.ts +0 -18
- package/src/share/utility-registry.yaml +0 -36
- package/src/share/vitest.config.ts +0 -8
- package/src/surface/blueprint-schema.ts +0 -314
- package/src/surface/blueprint-types.ts +0 -256
- /package/src/{share/agent → agent}/api-catalog.ts +0 -0
- /package/src/{share/agent → agent}/capability.ts +0 -0
- /package/src/{share/agent → agent}/dns-aid.ts +0 -0
- /package/src/{share/agent → agent}/fleet-catalog.ts +0 -0
- /package/src/{share/agent → agent}/index.ts +0 -0
- /package/src/{share/agent → agent}/knowledge.ts +0 -0
- /package/src/{share/agent → agent}/mcp-card.ts +0 -0
- /package/src/{share/agent → agent}/omit-empty.ts +0 -0
- /package/src/{share/agent → agent}/openapi.ts +0 -0
- /package/src/{share/agent → agent}/proof.ts +0 -0
- /package/src/{share/agent → agent}/search.test.ts +0 -0
- /package/src/{share → attribution}/attribution-display.ts +0 -0
- /package/src/{share/scripts → client-scripts}/gsap-mountain-journey.ts +0 -0
- /package/src/{share/scripts → client-scripts}/gsap-parallax.ts +0 -0
- /package/src/{share/scripts → client-scripts}/gsap-reveal.ts +0 -0
- /package/src/{share/scripts → client-scripts}/gsap-stagger.ts +0 -0
- /package/src/{share/scripts → client-scripts}/live-photos.ts +0 -0
- /package/src/{share/scripts → client-scripts}/video-player.ts +0 -0
- /package/src/{share/content → content}/resolve-field-path.ts +0 -0
- /package/src/{share/content → content}/substitute-deep.ts +0 -0
- /package/src/{share → content}/tests/content-ref-index.test.ts +0 -0
- /package/src/{share/content-discipline → content-discipline}/types.ts +0 -0
- /package/src/{share → image-provider}/image-provider.ts +0 -0
- /package/src/{share/knowledge → knowledge}/claim.ts +0 -0
- /package/src/{share/knowledge → knowledge}/derivation.ts +0 -0
- /package/src/{share/knowledge → knowledge}/freshness.ts +0 -0
- /package/src/{share/knowledge → knowledge}/index.ts +0 -0
- /package/src/{share/knowledge → knowledge}/ledger.ts +0 -0
- /package/src/{share/knowledge → knowledge}/plan.ts +0 -0
- /package/src/{share/knowledge → knowledge}/source.ts +0 -0
- /package/src/{share/legal → legal}/translation-policy.ts +0 -0
- /package/src/{share/middleware → middleware}/language-redirect.ts +0 -0
- /package/src/{share/middleware → middleware}/tests/access-protection.test.ts +0 -0
- /package/src/{share → node}/fs/index.ts +0 -0
- /package/src/{share/tests/markdown-twin-provenance.test.ts → node/tests/markdown-twin-provenance-0613.test.ts} +0 -0
- /package/src/{share → offers}/offer-capacity.ts +0 -0
- /package/src/{share/onboarding-yaml/index.ts → onboarding/yaml.ts} +0 -0
- /package/src/{share → ontology}/tests/ontology-role-by-cosmic-name.test.ts +0 -0
- /package/src/{share/routes → routes}/tests/template-filter.test.ts +0 -0
- /package/src/{share/schemas → schemas}/claim-records.ts +0 -0
- /package/src/{share/schemas → schemas}/horizontal-align.ts +0 -0
- /package/src/{share/schemas → schemas}/icon-color.ts +0 -0
- /package/src/{share/schemas → schemas}/live-photo.ts +0 -0
- /package/src/{share/schemas → schemas}/material-credit.ts +0 -0
- /package/src/{share/schemas → schemas}/media.ts +0 -0
- /package/src/{share/schemas → schemas}/participant.ts +0 -0
- /package/src/{share/schemas → schemas}/print.ts +0 -0
- /package/src/{share/schemas → schemas}/section-background.ts +0 -0
- /package/src/{share/schemas → schemas}/section-body.ts +0 -0
- /package/src/{share/schemas → schemas}/section-cards.ts +0 -0
- /package/src/{share/schemas → schemas}/section-cta.ts +0 -0
- /package/src/{share/schemas → schemas}/section-header.ts +0 -0
- /package/src/{share/schemas → schemas}/section-image.ts +0 -0
- /package/src/{share/schemas → schemas}/section-motion.ts +0 -0
- /package/src/{share/schemas → schemas}/section-shell.ts +0 -0
- /package/src/{share/schemas → schemas}/section-stats.ts +0 -0
- /package/src/{share/schemas → schemas}/site-background.ts +0 -0
- /package/src/{share/semantic → semantic}/ai.ts +0 -0
- /package/src/{share/semantic → semantic}/block-extraction.ts +0 -0
- /package/src/{share/semantic → semantic}/breadcrumbs.ts +0 -0
- /package/src/{share/semantic → semantic}/build-page.ts +0 -0
- /package/src/{share/semantic → semantic}/feed.ts +0 -0
- /package/src/{share/semantic → semantic}/image-sitemap.ts +0 -0
- /package/src/{share/semantic → semantic}/jsonld/article.ts +0 -0
- /package/src/{share/semantic → semantic}/jsonld/collection-list.ts +0 -0
- /package/src/{share/semantic → semantic}/jsonld/video.ts +0 -0
- /package/src/{share/semantic → semantic}/llms-policy.ts +0 -0
- /package/src/{share/semantic → semantic}/markdown-hygiene.ts +0 -0
- /package/src/{share/semantic → semantic}/output-projection.ts +0 -0
- /package/src/{share/semantic → semantic}/page-markdown.ts +0 -0
- /package/src/{share/semantic → semantic}/price-marker-resolver.ts +0 -0
- /package/src/{share/semantic → semantic}/robots.ts +0 -0
- /package/src/{share/semantic → semantic}/update-stamp.ts +0 -0
- /package/src/{share/slug → slug}/heading-slugger.ts +0 -0
- /package/src/{share/slug → slug}/index.ts +0 -0
- /package/src/{share/slug → slug}/slug-id.ts +0 -0
- /package/src/{share/slug → slug}/strategies.ts +0 -0
- /package/src/{share/slug → slug}/tests/slug.test.ts +0 -0
- /package/src/{share → text}/tests/text-normalize.pbt.test.ts +0 -0
- /package/src/{share → text}/text-position.ts +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>Maintains packages/share/src/string-utils.ts as an authored share authored module so agents can evolve it without rediscovering local boundaries.</purpose>
|
|
4
|
+
<non-goals>
|
|
5
|
+
<item>Do not introduce app-specific runtime composition or deployment behavior into this reusable package source file.</item>
|
|
6
|
+
</non-goals>
|
|
7
|
+
</MODULE_CONTRACT>
|
|
8
|
+
<CHANGE_SUMMARY>
|
|
9
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
10
|
+
|
|
11
|
+
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.</item>
|
|
12
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
13
|
+
|
|
14
|
+
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.</item>
|
|
15
|
+
</CHANGE_SUMMARY>
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/** Lowercase, dash-only kebab-case. Strips leading/trailing hyphens. */
|
|
19
|
+
export function toKebabCase(value: string): string {
|
|
20
|
+
return value
|
|
21
|
+
.toLowerCase()
|
|
22
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
23
|
+
.replace(/^-+|-+$/g, "");
|
|
24
|
+
}
|
|
@@ -36,6 +36,11 @@ test("quotes: curly + guillemets become straight", () => {
|
|
|
36
36
|
expect(normalizeText(input, ALL_ON)).toBe(`"hi" "yo" it's 'a' "de"`);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
+
test("quotes: U+02BC modifier letter apostrophe becomes straight (RFC-1070)", () => {
|
|
40
|
+
const input = "it\u02BCs";
|
|
41
|
+
expect(normalizeText(input, ALL_ON)).toBe("it's");
|
|
42
|
+
});
|
|
43
|
+
|
|
39
44
|
test("ellipsis: single char becomes three dots", () => {
|
|
40
45
|
expect(normalizeText("wait…", ALL_ON)).toBe("wait...");
|
|
41
46
|
});
|
|
@@ -18,6 +18,7 @@ never touched; this only transforms output strings.
|
|
|
18
18
|
<CHANGE_SUMMARY>
|
|
19
19
|
<item>RFC-0235: initial egress text normalizer.</item>
|
|
20
20
|
<item>RFC-0569: add createDevNormalizeMiddleware for dev/prod egress parity.</item>
|
|
21
|
+
<item>RFC-1070: add U+02BC modifier letter apostrophe to quotes signal.</item>
|
|
21
22
|
</CHANGE_SUMMARY>
|
|
22
23
|
*/
|
|
23
24
|
|
|
@@ -72,7 +73,7 @@ export const SIGNAL_REGISTRY: readonly SignalSpec[] = [
|
|
|
72
73
|
{
|
|
73
74
|
id: "quotes",
|
|
74
75
|
title: "Typographic / smart quotes",
|
|
75
|
-
unicode: "U+00AB U+00BB U+2018-U+201F",
|
|
76
|
+
unicode: "U+00AB U+00BB U+2018-U+201F U+02BC",
|
|
76
77
|
replacement: "straight double / single quote",
|
|
77
78
|
default: true,
|
|
78
79
|
},
|
|
@@ -148,8 +149,8 @@ export function resolveNormalizeConfig(manifest: unknown): NormalizeConfig {
|
|
|
148
149
|
const RE_DASHES = /[‐‑‒–—―−]/g;
|
|
149
150
|
// U+00AB U+00BB U+201C U+201D U+201E U+201F
|
|
150
151
|
const RE_QUOTES_DOUBLE = /[«»“”„‟]/g;
|
|
151
|
-
// U+2018 U+2019 U+201A U+201B
|
|
152
|
-
const RE_QUOTES_SINGLE = /[
|
|
152
|
+
// U+2018 U+2019 U+201A U+201B U+02BC (modifier letter apostrophe, RFC-1070)
|
|
153
|
+
const RE_QUOTES_SINGLE = /[‘’‚‛ʼ]/g;
|
|
153
154
|
const RE_ELLIPSIS = /…/g;
|
|
154
155
|
// U+00A0 nbsp, U+1680 ogham, U+2000-U+200A, U+202F narrow nbsp, U+205F medium math,
|
|
155
156
|
// U+3000 ideographic space.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
</non-goals>
|
|
9
9
|
</MODULE_CONTRACT>
|
|
10
10
|
<CHANGE_SUMMARY>
|
|
11
|
-
<item>RFC-0041: Created as SSR inline number pre-wrap utility in @warpgogol/werkstatt-shared/
|
|
11
|
+
<item>RFC-0041: Created as SSR inline number pre-wrap utility in @warpgogol/werkstatt-shared/text.</item>
|
|
12
12
|
</CHANGE_SUMMARY>
|
|
13
13
|
*/
|
|
14
14
|
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>axiom-study.d.ts — ambient module declaration for the external @syrokomskyi/axiom-study package types.</purpose>
|
|
4
|
+
<non-goals>
|
|
5
|
+
<item>Do not implement runtime code — this file only declares types for an external package.</item>
|
|
6
|
+
</non-goals>
|
|
7
|
+
</MODULE_CONTRACT>
|
|
8
|
+
<CHANGE_SUMMARY>
|
|
9
|
+
<item>RFC-1097: sweep — tail packages clean
|
|
10
|
+
|
|
11
|
+
Sweep batch 3: rewrote ~95 purposes across werkstatt-knowledge, werkstatt-shared, godot-game, phaser-game, lifecycle-core, projektarchiv-*, portal-*, billing-*, typescript (CONTRACT-02/PURPOSE-02). Real KEY_DECISIONS on 5 godot utils, non-goals on 5 CONTRACT-03 files, headers on 4 headerless files, CS-07 history literal fix on 2 files. Policy: vitest.config.ts + test-fixtures testPatterns, worker-configuration.d.ts excludedPath. All non-site/engine packages now 0 diagnostics.</item>
|
|
12
|
+
</CHANGE_SUMMARY>
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
declare module "@syrokomskyi/axiom-study" {
|
|
16
|
+
export interface Finding {
|
|
17
|
+
findingId: string;
|
|
18
|
+
semanticFingerprint: { algorithm: "sha256"; digest: string; size: number; mediaType: string };
|
|
19
|
+
methodologyId: string;
|
|
20
|
+
ruleId: string;
|
|
21
|
+
affectedSubjectId: string;
|
|
22
|
+
title: string;
|
|
23
|
+
severity: "info" | "low" | "medium" | "high" | "critical";
|
|
24
|
+
evidence: Array<{
|
|
25
|
+
evidenceRef: {
|
|
26
|
+
artifactId: string;
|
|
27
|
+
rootDigest: { algorithm: "sha256"; digest: string; size: number; mediaType: string };
|
|
28
|
+
schema: string;
|
|
29
|
+
};
|
|
30
|
+
selector: string;
|
|
31
|
+
evidenceClass: string;
|
|
32
|
+
}>;
|
|
33
|
+
uncertainty: unknown[];
|
|
34
|
+
extension: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>Type shim for the official `hls.js/light` export used by the lazy feature-video runtime.</purpose>
|
|
4
|
+
<non-goals>
|
|
5
|
+
<item>Do not change runtime resolution; this file only fills the missing package declaration.</item>
|
|
6
|
+
</non-goals>
|
|
7
|
+
</MODULE_CONTRACT>
|
|
8
|
+
<CHANGE_SUMMARY>
|
|
9
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
10
|
+
|
|
11
|
+
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.</item>
|
|
12
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
13
|
+
|
|
14
|
+
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.</item>
|
|
15
|
+
</CHANGE_SUMMARY>
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
declare module "hls.js/light" {
|
|
19
|
+
export { default } from "hls.js";
|
|
20
|
+
export * from "hls.js";
|
|
21
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>Type shim for the qrcode browser entry point (qrcode/lib/browser.js).
|
|
4
|
+
The qrcode package only ships types for its main entry, but the browser entry
|
|
5
|
+
exports the same toCanvas function. This shim re-exports all types from qrcode
|
|
6
|
+
so the client-side QR code script gets full type safety.</purpose>
|
|
7
|
+
<non-goals>
|
|
8
|
+
<item>Do not change runtime resolution; this file only fills the missing package declaration.</item>
|
|
9
|
+
</non-goals>
|
|
10
|
+
</MODULE_CONTRACT>
|
|
11
|
+
<CHANGE_SUMMARY>
|
|
12
|
+
<item>RFC-1097: step 6 — compass.migrate codemod run
|
|
13
|
+
|
|
14
|
+
Mechanical v1 to v2 header migration across the workspace: 942 files rewritten — CHANGE_SUMMARY windows collapsed into history, forbidden v1 blocks stripped, KEY_DECISIONS seeded from @ai-invariant comments (5 files) or TODO placeholders (103 files), blocks reordered to canonical order.</item>
|
|
15
|
+
<item>RFC-1097: sweep — werkstatt-engine clean
|
|
16
|
+
|
|
17
|
+
Sweep batch 4: 73 Compass headers on headerless engine files (certification, component-runtime, isolation, evolution, testing), real KEY_DECISIONS on 75 files (kernel, cache, dht, swim, gitmesh, runtime), ~80 purpose expansions (CONTRACT-02/PURPOSE-02), non-goals on 13 CONTRACT-03 files, CS-07 history literal fix repo-wide (253 files). Policy: .template.ts/.template.astro excludedPaths. werkstatt-engine now 0 diagnostics.</item>
|
|
18
|
+
</CHANGE_SUMMARY>
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
declare module "qrcode/lib/browser.js" {
|
|
22
|
+
export * from "qrcode";
|
|
23
|
+
}
|
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import fc from "fast-check";
|
|
3
|
+
import { applyFixes, FIXABLE_RULE_IDS, isFixable } from "./fix.ts";
|
|
4
|
+
import {
|
|
5
|
+
TIER1_RULES,
|
|
6
|
+
createTypographyContext,
|
|
7
|
+
type TypographyFinding,
|
|
8
|
+
type TypographyRule,
|
|
9
|
+
} from "./rules-tier1.ts";
|
|
10
|
+
import { TIER2_LOCALE_RULES } from "./rules-tier2-locale.ts";
|
|
11
|
+
import type { TextSegment } from "./text-surface.ts";
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Helpers
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
function makeSegment(text: string, locale = "de"): TextSegment {
|
|
18
|
+
return {
|
|
19
|
+
file: "test.md",
|
|
20
|
+
line: 1,
|
|
21
|
+
path: "$body",
|
|
22
|
+
source: "body",
|
|
23
|
+
text,
|
|
24
|
+
raw: text,
|
|
25
|
+
isTableRow: false,
|
|
26
|
+
locale,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const ALL_FIXABLE_RULES: readonly TypographyRule[] = [...TIER1_RULES, ...TIER2_LOCALE_RULES].filter(
|
|
31
|
+
(rule) => isFixable(rule.id),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
function runFixableRules(text: string, locale: string): TypographyFinding[] {
|
|
35
|
+
const segment = makeSegment(text, locale);
|
|
36
|
+
const ctx = createTypographyContext(locale, new Set());
|
|
37
|
+
const findings: TypographyFinding[] = [];
|
|
38
|
+
for (const rule of ALL_FIXABLE_RULES) {
|
|
39
|
+
if (rule.id === "TYPO-ABBR-02" && locale !== "de") continue;
|
|
40
|
+
if ((rule.id === "TYPO-APOS-01" || rule.id === "TYPO-APOS-02") && locale !== "uk") continue;
|
|
41
|
+
findings.push(...rule.check(segment, ctx));
|
|
42
|
+
}
|
|
43
|
+
return findings;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
// Property tests (DNA-101: idempotency)
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
describe("Fix engine — property-based tests (RFC-1072, DNA-101)", () => {
|
|
51
|
+
it("FIXABLE_RULE_IDS contains exactly 7 rule IDs", () => {
|
|
52
|
+
expect(FIXABLE_RULE_IDS).toHaveLength(7);
|
|
53
|
+
expect(FIXABLE_RULE_IDS).toContain("TYPO-PUNCT-01");
|
|
54
|
+
expect(FIXABLE_RULE_IDS).toContain("TYPO-SPACE-01");
|
|
55
|
+
expect(FIXABLE_RULE_IDS).toContain("TYPO-SPACE-02");
|
|
56
|
+
expect(FIXABLE_RULE_IDS).toContain("TYPO-APOS-01");
|
|
57
|
+
expect(FIXABLE_RULE_IDS).toContain("TYPO-APOS-02");
|
|
58
|
+
expect(FIXABLE_RULE_IDS).toContain("TYPO-ABBR-01");
|
|
59
|
+
expect(FIXABLE_RULE_IDS).toContain("TYPO-ABBR-02");
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it("isFixable returns true only for whitelisted rules", () => {
|
|
63
|
+
for (const id of FIXABLE_RULE_IDS) {
|
|
64
|
+
expect(isFixable(id)).toBe(true);
|
|
65
|
+
}
|
|
66
|
+
expect(isFixable("TYPO-PUNCT-02")).toBe(false);
|
|
67
|
+
expect(isFixable("TYPO-CASE-01")).toBe(false);
|
|
68
|
+
expect(isFixable("TYPO-UNICODE-01")).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("applyFixes is idempotent: fixing an already-fixed text produces no new fixes", () => {
|
|
72
|
+
fc.assert(
|
|
73
|
+
fc.property(
|
|
74
|
+
fc.oneof(
|
|
75
|
+
fc.constant("Hello world"), // SPACE-01
|
|
76
|
+
fc.constant("Hello "), // SPACE-02
|
|
77
|
+
fc.constant("Hello,, world"), // PUNCT-01
|
|
78
|
+
fc.constant("Hello:: world"), // PUNCT-01
|
|
79
|
+
fc.constant("z.B. Hallo"), // ABBR-02 (de)
|
|
80
|
+
fc.constant("z. B. Hallo"), // already fixed ABBR-02
|
|
81
|
+
),
|
|
82
|
+
(text) => {
|
|
83
|
+
const findings1 = runFixableRules(text, "de");
|
|
84
|
+
const { fixedSegments } = applyFixes(findings1, createTypographyContext("de", new Set()));
|
|
85
|
+
const fixedText = fixedSegments.get("test.md:1:$body") ?? text;
|
|
86
|
+
|
|
87
|
+
// Running fixable rules on the fixed text should produce zero fixable findings
|
|
88
|
+
const findings2 = runFixableRules(fixedText, "de");
|
|
89
|
+
const fixableFindings2 = findings2.filter((f) => f.fix !== null);
|
|
90
|
+
expect(fixableFindings2).toHaveLength(0);
|
|
91
|
+
},
|
|
92
|
+
),
|
|
93
|
+
{ numRuns: 100 },
|
|
94
|
+
);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("applyFixes with no fixable findings returns empty map", () => {
|
|
98
|
+
const findings: TypographyFinding[] = [];
|
|
99
|
+
const ctx = createTypographyContext("de", new Set());
|
|
100
|
+
const result = applyFixes(findings, ctx);
|
|
101
|
+
expect(result.fixedSegments.size).toBe(0);
|
|
102
|
+
expect(result.fixCount).toBe(0);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("applyFixes skips findings with fix: null", () => {
|
|
106
|
+
const segment = makeSegment("Hello world", "de");
|
|
107
|
+
const findings: TypographyFinding[] = [
|
|
108
|
+
{
|
|
109
|
+
ruleId: "TYPO-PUNCT-02",
|
|
110
|
+
segment,
|
|
111
|
+
match: "..",
|
|
112
|
+
column: 5,
|
|
113
|
+
message: "test",
|
|
114
|
+
fixHint: "test",
|
|
115
|
+
fix: null,
|
|
116
|
+
},
|
|
117
|
+
];
|
|
118
|
+
const ctx = createTypographyContext("de", new Set());
|
|
119
|
+
const result = applyFixes(findings, ctx);
|
|
120
|
+
expect(result.fixedSegments.size).toBe(0);
|
|
121
|
+
expect(result.fixCount).toBe(0);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("replace action replaces the match at the given column", () => {
|
|
125
|
+
const segment = makeSegment("Hello,, world", "de");
|
|
126
|
+
const findings: TypographyFinding[] = [
|
|
127
|
+
{
|
|
128
|
+
ruleId: "TYPO-PUNCT-01",
|
|
129
|
+
segment,
|
|
130
|
+
match: ",,",
|
|
131
|
+
column: 5,
|
|
132
|
+
message: "test",
|
|
133
|
+
fixHint: "test",
|
|
134
|
+
fix: { type: "replace", old: ",,", new: "," },
|
|
135
|
+
},
|
|
136
|
+
];
|
|
137
|
+
const ctx = createTypographyContext("de", new Set());
|
|
138
|
+
const result = applyFixes(findings, ctx);
|
|
139
|
+
const fixed = result.fixedSegments.get("test.md:1:$body");
|
|
140
|
+
expect(fixed).toBe("Hello, world");
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("insert action inserts text at the specified position", () => {
|
|
144
|
+
const segment = makeSegment("zB Hallo", "de");
|
|
145
|
+
const findings: TypographyFinding[] = [
|
|
146
|
+
{
|
|
147
|
+
ruleId: "TYPO-ABBR-01",
|
|
148
|
+
segment,
|
|
149
|
+
match: "zB",
|
|
150
|
+
column: 0,
|
|
151
|
+
message: "test",
|
|
152
|
+
fixHint: "test",
|
|
153
|
+
fix: { type: "insert", at: 2, text: "." },
|
|
154
|
+
},
|
|
155
|
+
];
|
|
156
|
+
const ctx = createTypographyContext("de", new Set());
|
|
157
|
+
const result = applyFixes(findings, ctx);
|
|
158
|
+
const fixed = result.fixedSegments.get("test.md:1:$body");
|
|
159
|
+
expect(fixed).toBe("zB. Hallo");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("delete action removes characters at the specified position", () => {
|
|
163
|
+
const segment = makeSegment("Hello ", "de");
|
|
164
|
+
const findings: TypographyFinding[] = [
|
|
165
|
+
{
|
|
166
|
+
ruleId: "TYPO-SPACE-02",
|
|
167
|
+
segment,
|
|
168
|
+
match: " ",
|
|
169
|
+
column: 5,
|
|
170
|
+
message: "test",
|
|
171
|
+
fixHint: "test",
|
|
172
|
+
fix: { type: "delete", at: 5, length: 3 },
|
|
173
|
+
},
|
|
174
|
+
];
|
|
175
|
+
const ctx = createTypographyContext("de", new Set());
|
|
176
|
+
const result = applyFixes(findings, ctx);
|
|
177
|
+
const fixed = result.fixedSegments.get("test.md:1:$body");
|
|
178
|
+
expect(fixed).toBe("Hello");
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it("multiple fixes in the same segment are applied correctly (right-to-left)", () => {
|
|
182
|
+
const segment = makeSegment("Hello,, world", "de");
|
|
183
|
+
const findings: TypographyFinding[] = [
|
|
184
|
+
{
|
|
185
|
+
ruleId: "TYPO-PUNCT-01",
|
|
186
|
+
segment,
|
|
187
|
+
match: ",,",
|
|
188
|
+
column: 5,
|
|
189
|
+
message: "test",
|
|
190
|
+
fixHint: "test",
|
|
191
|
+
fix: { type: "replace", old: ",,", new: "," },
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
ruleId: "TYPO-SPACE-01",
|
|
195
|
+
segment,
|
|
196
|
+
match: " w",
|
|
197
|
+
column: 7,
|
|
198
|
+
message: "test",
|
|
199
|
+
fixHint: "test",
|
|
200
|
+
fix: { type: "replace", old: " w", new: " w" },
|
|
201
|
+
},
|
|
202
|
+
];
|
|
203
|
+
const ctx = createTypographyContext("de", new Set());
|
|
204
|
+
const result = applyFixes(findings, ctx);
|
|
205
|
+
const fixed = result.fixedSegments.get("test.md:1:$body");
|
|
206
|
+
expect(fixed).toBe("Hello, world");
|
|
207
|
+
});
|
|
208
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>Mechanical fix engine for typography violations (RFC-1072). Provides the
|
|
4
|
+
FixAction discriminated union, the FIXABLE_RULE_IDS whitelist, and the applyFixes
|
|
5
|
+
pure function that transforms findings into fixed segment text. Only rules
|
|
6
|
+
whitelisted in FIXABLE_RULE_IDS populate the fix field on TypographyFinding.</purpose>
|
|
7
|
+
<non-goals>
|
|
8
|
+
<item>Do not read or write files — that is the command adapter in werkstatt-site.</item>
|
|
9
|
+
<item>Do not run convergence guards — the command adapter re-runs typography.validate.</item>
|
|
10
|
+
<item>Do not fix rules outside the whitelist — those require human judgment.</item>
|
|
11
|
+
</non-goals>
|
|
12
|
+
</MODULE_CONTRACT>
|
|
13
|
+
<CHANGE_SUMMARY>
|
|
14
|
+
<item>RFC-1072: initial creation with FixAction type, FIXABLE_RULE_IDS, and applyFixes.</item>
|
|
15
|
+
</CHANGE_SUMMARY>
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { TextSegment } from "./text-surface.ts";
|
|
19
|
+
import type { TypographyFinding, TypographyContext } from "./rules-tier1.ts";
|
|
20
|
+
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// FixAction: discriminated union for mechanical fix actions
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Discriminated union for mechanical fix actions.
|
|
27
|
+
* Stored on `TypographyFinding.fix` (replacing `null` from RFC-1068).
|
|
28
|
+
* Only rules whitelisted in FIXABLE_RULE_IDS populate this field;
|
|
29
|
+
* all other rules keep `fix: null`.
|
|
30
|
+
*/
|
|
31
|
+
export type FixAction =
|
|
32
|
+
| { type: "replace"; old: string; new: string }
|
|
33
|
+
| { type: "insert"; at: number; text: string }
|
|
34
|
+
| { type: "delete"; at: number; length: number };
|
|
35
|
+
|
|
36
|
+
// ---------------------------------------------------------------------------
|
|
37
|
+
// Whitelist of fixable rule IDs (RFC-1072)
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Rules that are safe for mechanical fixing. Only PUNCT, SPACE, APOS, and ABBR
|
|
42
|
+
* families are fixable — other families require human judgment.
|
|
43
|
+
*/
|
|
44
|
+
export const FIXABLE_RULE_IDS: readonly string[] = [
|
|
45
|
+
"TYPO-PUNCT-01",
|
|
46
|
+
"TYPO-SPACE-01",
|
|
47
|
+
"TYPO-SPACE-02",
|
|
48
|
+
"TYPO-APOS-01",
|
|
49
|
+
"TYPO-APOS-02",
|
|
50
|
+
"TYPO-ABBR-01",
|
|
51
|
+
"TYPO-ABBR-02",
|
|
52
|
+
] as const;
|
|
53
|
+
|
|
54
|
+
const FIXABLE_SET: ReadonlySet<string> = new Set(FIXABLE_RULE_IDS);
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if a rule ID is in the fixable whitelist.
|
|
58
|
+
*/
|
|
59
|
+
export function isFixable(ruleId: string): boolean {
|
|
60
|
+
return FIXABLE_SET.has(ruleId);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// ---------------------------------------------------------------------------
|
|
64
|
+
// Segment identity key (for Map<TextSegment, string>)
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
function segmentKey(segment: TextSegment): string {
|
|
68
|
+
return `${segment.file}:${segment.line}:${segment.path}`;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// ---------------------------------------------------------------------------
|
|
72
|
+
// Apply a single fix action to segment text
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
|
|
75
|
+
function applyAction(text: string, action: FixAction, column: number): string {
|
|
76
|
+
switch (action.type) {
|
|
77
|
+
case "replace": {
|
|
78
|
+
// Replace the match at the given column
|
|
79
|
+
const before = text.slice(0, column);
|
|
80
|
+
const after = text.slice(column + action.old.length);
|
|
81
|
+
return before + action.new + after;
|
|
82
|
+
}
|
|
83
|
+
case "insert": {
|
|
84
|
+
// Insert text at the specified position (relative to segment text)
|
|
85
|
+
const before = text.slice(0, action.at);
|
|
86
|
+
const after = text.slice(action.at);
|
|
87
|
+
return before + action.text + after;
|
|
88
|
+
}
|
|
89
|
+
case "delete": {
|
|
90
|
+
// Delete `length` characters starting at `at`
|
|
91
|
+
const before = text.slice(0, action.at);
|
|
92
|
+
const after = text.slice(action.at + action.length);
|
|
93
|
+
return before + after;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// applyFixes: apply all fixes to findings, returning fixed segment text
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Apply mechanical fixes to findings. Each finding must have a non-null `fix`
|
|
104
|
+
* (populated by the rule when whitelisted in FIXABLE_RULE_IDS).
|
|
105
|
+
*
|
|
106
|
+
* The function groups findings by segment, then applies all fixes within a
|
|
107
|
+
* segment in reverse column order (to avoid offset shifts). Returns a Map keyed
|
|
108
|
+
* by segment identity, with the full fixed segment text as the value.
|
|
109
|
+
*
|
|
110
|
+
* Findings with `fix: null` (non-whitelisted rules) are skipped.
|
|
111
|
+
*/
|
|
112
|
+
export function applyFixes(
|
|
113
|
+
findings: TypographyFinding[],
|
|
114
|
+
_context: TypographyContext,
|
|
115
|
+
): { fixedSegments: Map<string, string>; fixCount: number } {
|
|
116
|
+
// Group findings by segment key
|
|
117
|
+
const bySegment = new Map<string, { segment: TextSegment; findings: TypographyFinding[] }>();
|
|
118
|
+
|
|
119
|
+
for (const f of findings) {
|
|
120
|
+
if (f.fix === null) continue;
|
|
121
|
+
const key = segmentKey(f.segment);
|
|
122
|
+
let entry = bySegment.get(key);
|
|
123
|
+
if (!entry) {
|
|
124
|
+
entry = { segment: f.segment, findings: [] };
|
|
125
|
+
bySegment.set(key, entry);
|
|
126
|
+
}
|
|
127
|
+
entry.findings.push(f);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const fixedSegments = new Map<string, string>();
|
|
131
|
+
let fixCount = 0;
|
|
132
|
+
|
|
133
|
+
for (const [key, { segment, findings: segFindings }] of bySegment) {
|
|
134
|
+
// Sort findings by column in descending order to apply from right to left
|
|
135
|
+
const sorted = [...segFindings].sort((a, b) => b.column - a.column);
|
|
136
|
+
|
|
137
|
+
let text = segment.text;
|
|
138
|
+
for (const f of sorted) {
|
|
139
|
+
if (f.fix === null) continue;
|
|
140
|
+
text = applyAction(text, f.fix, f.column);
|
|
141
|
+
fixCount++;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
fixedSegments.set(key, text);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return { fixedSegments, fixCount };
|
|
148
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>Barrel export for the typography module (RFC-1068, RFC-1069, RFC-1070,
|
|
4
|
+
RFC-1071). Provides the text-surface extractor, Tier 1, Tier 2, and Tier 3 rule
|
|
5
|
+
engines, and locale defaults for the typography.validate command and future
|
|
6
|
+
typography rule families.</purpose>
|
|
7
|
+
<non-goals>
|
|
8
|
+
<item>Do not implement command adapters — that lives in werkstatt-site.</item>
|
|
9
|
+
</non-goals>
|
|
10
|
+
</MODULE_CONTRACT>
|
|
11
|
+
<CHANGE_SUMMARY>
|
|
12
|
+
<item>RFC-1068: initial creation.</item>
|
|
13
|
+
<item>RFC-1069: added Tier 2 structure rules export.</item>
|
|
14
|
+
<item>RFC-1070: added Tier 2 locale rules export.</item>
|
|
15
|
+
<item>RFC-1071: added Tier 3 advisory rules export.</item>
|
|
16
|
+
<item>RFC-1072: added fix module export (FixAction, FIXABLE_RULE_IDS, applyFixes, isFixable).</item>
|
|
17
|
+
</CHANGE_SUMMARY>
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
extractTextSurface,
|
|
22
|
+
TECHNICAL_KEYS,
|
|
23
|
+
deriveFileLocale,
|
|
24
|
+
type TextSegment,
|
|
25
|
+
type TextSegmentSource,
|
|
26
|
+
type TextSurfaceOptions,
|
|
27
|
+
type YamlError,
|
|
28
|
+
type ExtractTextSurfaceResult,
|
|
29
|
+
} from "./text-surface.ts";
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
TIER1_RULES,
|
|
33
|
+
DEFAULT_ALLOWED_TOKENS,
|
|
34
|
+
createTypographyContext,
|
|
35
|
+
type TypographyRuleId,
|
|
36
|
+
type TypographyRuleFamily,
|
|
37
|
+
type TypographyFinding,
|
|
38
|
+
type TypographyRule,
|
|
39
|
+
type TypographyContext,
|
|
40
|
+
} from "./rules-tier1.ts";
|
|
41
|
+
|
|
42
|
+
export { TIER2_STRUCTURE_RULES } from "./rules-tier2-structure.ts";
|
|
43
|
+
|
|
44
|
+
export { TIER2_LOCALE_RULES, type Tier2LocaleRuleId } from "./rules-tier2-locale.ts";
|
|
45
|
+
|
|
46
|
+
export { TIER3_ADVISORY_RULES, type Tier3AdvisoryRuleId } from "./rules-tier3-advisory.ts";
|
|
47
|
+
|
|
48
|
+
export {
|
|
49
|
+
LOCALE_DEFAULTS,
|
|
50
|
+
getLocaleDefaults,
|
|
51
|
+
type LocaleTypographyDefaults,
|
|
52
|
+
} from "./locale-defaults.ts";
|
|
53
|
+
|
|
54
|
+
export { type FixAction, FIXABLE_RULE_IDS, isFixable, applyFixes } from "./fix.ts";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
<MODULE_CONTRACT>
|
|
3
|
+
<purpose>Locale-specific typography defaults for the typography rule engine.
|
|
4
|
+
Exports abbreviation sets, number format defaults, and apostrophe policy keyed
|
|
5
|
+
by locale code (RFC-1068, RFC-1070).</purpose>
|
|
6
|
+
<non-goals>
|
|
7
|
+
<item>Do not define typography rules — only locale-specific data.</item>
|
|
8
|
+
<item>Do not read system.md or site configuration.</item>
|
|
9
|
+
</non-goals>
|
|
10
|
+
</MODULE_CONTRACT>
|
|
11
|
+
<CHANGE_SUMMARY>
|
|
12
|
+
<item>RFC-1068: initial creation with de, uk, en abbreviation sets.</item>
|
|
13
|
+
<item>RFC-1070: added numberFormat and apostrophePolicy to LocaleTypographyDefaults.</item>
|
|
14
|
+
</CHANGE_SUMMARY>
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
export interface LocaleTypographyDefaults {
|
|
18
|
+
/** Abbreviations ending with a period, used for TYPO-CASE-02 exclusion. */
|
|
19
|
+
abbreviations: ReadonlySet<string>;
|
|
20
|
+
/** Number format defaults for TYPO-NUM rules. Added by RFC-1070. */
|
|
21
|
+
numberFormat: {
|
|
22
|
+
decimalSeparator: "," | ".";
|
|
23
|
+
thousandsSeparator: "." | "," | " " | "\u202F";
|
|
24
|
+
};
|
|
25
|
+
/** Apostrophe policy for TYPO-APOS rules. Added by RFC-1070. */
|
|
26
|
+
apostrophePolicy: "straight" | "modifier";
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const DE_ABBREVIATIONS = new Set([
|
|
30
|
+
"z. B.",
|
|
31
|
+
"u. a.",
|
|
32
|
+
"d. h.",
|
|
33
|
+
"bzw.",
|
|
34
|
+
"ca.",
|
|
35
|
+
"inkl.",
|
|
36
|
+
"exkl.",
|
|
37
|
+
"ggf.",
|
|
38
|
+
"evtl.",
|
|
39
|
+
"vgl.",
|
|
40
|
+
"usw.",
|
|
41
|
+
"etc.",
|
|
42
|
+
"Nr.",
|
|
43
|
+
"Abs.",
|
|
44
|
+
"Std.",
|
|
45
|
+
"Min.",
|
|
46
|
+
"Str.",
|
|
47
|
+
"vs.",
|
|
48
|
+
"lit.",
|
|
49
|
+
"Art.",
|
|
50
|
+
"Inc.",
|
|
51
|
+
"e.V.",
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
const UK_ABBREVIATIONS = new Set([
|
|
55
|
+
"напр.",
|
|
56
|
+
"тис.",
|
|
57
|
+
"грн",
|
|
58
|
+
"т. ч.",
|
|
59
|
+
"ст.",
|
|
60
|
+
"п.",
|
|
61
|
+
"р.",
|
|
62
|
+
"див.",
|
|
63
|
+
"Див.",
|
|
64
|
+
"нім.",
|
|
65
|
+
"Inc.",
|
|
66
|
+
"e.V.",
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
const EN_ABBREVIATIONS = new Set(["e.g.", "i.e.", "etc.", "vs.", "No.", "Inc.", "e.V."]);
|
|
70
|
+
|
|
71
|
+
export const LOCALE_DEFAULTS: Record<string, LocaleTypographyDefaults> = {
|
|
72
|
+
de: {
|
|
73
|
+
abbreviations: DE_ABBREVIATIONS,
|
|
74
|
+
numberFormat: { decimalSeparator: ",", thousandsSeparator: "." },
|
|
75
|
+
apostrophePolicy: "straight",
|
|
76
|
+
},
|
|
77
|
+
uk: {
|
|
78
|
+
abbreviations: UK_ABBREVIATIONS,
|
|
79
|
+
numberFormat: { decimalSeparator: ",", thousandsSeparator: "\u202F" },
|
|
80
|
+
apostrophePolicy: "straight",
|
|
81
|
+
},
|
|
82
|
+
en: {
|
|
83
|
+
abbreviations: EN_ABBREVIATIONS,
|
|
84
|
+
numberFormat: { decimalSeparator: ".", thousandsSeparator: "," },
|
|
85
|
+
apostrophePolicy: "straight",
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export function getLocaleDefaults(locale: string): LocaleTypographyDefaults {
|
|
90
|
+
return (
|
|
91
|
+
LOCALE_DEFAULTS[locale] ?? {
|
|
92
|
+
abbreviations: new Set(),
|
|
93
|
+
numberFormat: { decimalSeparator: ".", thousandsSeparator: "," },
|
|
94
|
+
apostrophePolicy: "straight",
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
}
|