@pixelated-tech/components 3.6.0 → 3.7.1
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 +25 -0
- package/dist/components/admin/site-health/site-health-mock-context.js +15 -0
- package/dist/components/admin/site-health/site-health-template.js +35 -2
- package/dist/components/{seo → general}/404.js +1 -1
- package/dist/components/{callout → general}/callout.js +1 -1
- package/dist/components/{carousel → general}/carousel.js +1 -1
- package/dist/components/{cms → general}/contentful.items.components.js +2 -2
- package/dist/components/{cms → general}/gravatar.components.js +1 -1
- package/dist/components/{cms → general}/instagram.components.js +2 -2
- package/dist/components/{structured → general}/markdown.js +1 -1
- package/dist/components/{structured → general}/recipe.js +1 -1
- package/dist/components/{structured → general}/resume.js +1 -1
- package/dist/components/general/semantic.js +1 -1
- package/dist/components/{seo → general}/sitemap.js +2 -2
- package/dist/components/{cms → general}/smartimage.js +1 -1
- package/dist/components/{structured → general}/socialcard.js +1 -1
- package/dist/components/general/table.js +1 -1
- package/dist/components/{carousel → general}/tiles.js +1 -1
- package/dist/components/{structured → general}/timeline.js +1 -1
- package/dist/components/{cms → general}/wordpress.components.js +2 -2
- package/dist/components/shoppingcart/ebay.components.js +3 -3
- package/dist/components/shoppingcart/ebay.functions.js +1 -1
- package/dist/components/shoppingcart/shoppingcart.components.js +2 -2
- package/dist/components/shoppingcart/shoppingcart.functions.js +1 -1
- package/dist/components/sitebuilder/page/lib/componentMap.js +1 -1
- package/dist/components/sitebuilder/page/lib/componentMetadata.js +1 -1
- package/dist/components/sitebuilder/page/lib/pageStorageContentful.js +2 -2
- package/dist/index.adminclient.js +1 -0
- package/dist/index.adminserver.js +1 -1
- package/dist/index.js +48 -48
- package/dist/index.server.js +19 -21
- package/dist/mocks/browser.js +1 -0
- package/dist/mocks/handlers.js +206 -0
- package/dist/mocks/index.js +1 -0
- package/dist/scripts/generate-site-images.js +31 -0
- package/dist/scripts/proptypes-inferprops.js +205 -0
- package/dist/scripts/release.sh +194 -0
- package/dist/scripts/validate-exports.js +280 -0
- package/dist/types/components/admin/site-health/site-health-mock-context.d.ts +18 -0
- package/dist/types/components/admin/site-health/site-health-mock-context.d.ts.map +1 -0
- package/dist/types/components/admin/site-health/site-health-template.d.ts +1 -0
- package/dist/types/components/admin/site-health/site-health-template.d.ts.map +1 -1
- package/dist/types/components/general/404.d.ts.map +1 -0
- package/dist/types/components/general/buzzwordbingo.d.ts.map +1 -0
- package/dist/types/components/general/buzzwordbingo.words.d.ts.map +1 -0
- package/dist/types/components/general/calendly.d.ts.map +1 -0
- package/dist/types/components/{callout → general}/callout.d.ts.map +1 -1
- package/dist/types/components/general/carousel.d.ts.map +1 -0
- package/dist/types/components/general/carousel.drag.d.ts.map +1 -0
- package/dist/types/components/general/cloudinary.d.ts.map +1 -0
- package/dist/types/components/general/contentful.delivery.d.ts.map +1 -0
- package/dist/types/components/general/contentful.items.components.d.ts.map +1 -0
- package/dist/types/components/general/contentful.management.d.ts.map +1 -0
- package/dist/types/components/general/faq-accordion.d.ts.map +1 -0
- package/dist/types/components/{cms → general}/flickr.d.ts +1 -1
- package/dist/types/components/general/flickr.d.ts.map +1 -0
- package/dist/types/components/general/google.reviews.components.d.ts.map +1 -0
- package/dist/types/components/general/google.reviews.functions.d.ts.map +1 -0
- package/dist/types/components/general/googleanalytics.d.ts.map +1 -0
- package/dist/types/components/general/googlemap.d.ts.map +1 -0
- package/dist/types/components/general/googlesearch.d.ts.map +1 -0
- package/dist/types/components/general/gravatar.components.d.ts.map +1 -0
- package/dist/types/components/general/gravatar.functions.d.ts.map +1 -0
- package/dist/types/components/general/hubspot.components.d.ts.map +1 -0
- package/dist/types/components/general/instagram.components.d.ts.map +1 -0
- package/dist/types/components/{cms → general}/instagram.functions.d.ts +1 -1
- package/dist/types/components/general/instagram.functions.d.ts.map +1 -0
- package/dist/types/components/general/manifest.d.ts.map +1 -0
- package/dist/types/components/general/markdown.d.ts.map +1 -0
- package/dist/types/components/general/menu-accordion.d.ts.map +1 -0
- package/dist/types/components/general/menu-expando.d.ts.map +1 -0
- package/dist/types/components/general/menu-simple.d.ts.map +1 -0
- package/dist/types/components/general/metadata.components.d.ts.map +1 -0
- package/dist/types/components/general/metadata.functions.d.ts.map +1 -0
- package/dist/types/components/general/nerdjoke.d.ts.map +1 -0
- package/dist/types/components/general/recipe.d.ts.map +1 -0
- package/dist/types/components/general/resume.d.ts.map +1 -0
- package/dist/types/components/general/schema-blogposting.d.ts.map +1 -0
- package/dist/types/components/{seo → general}/schema-blogposting.functions.d.ts +1 -1
- package/dist/types/components/general/schema-blogposting.functions.d.ts.map +1 -0
- package/dist/types/components/general/schema-faq.d.ts.map +1 -0
- package/dist/types/components/general/schema-localbusiness.d.ts.map +1 -0
- package/dist/types/components/general/schema-recipe.d.ts.map +1 -0
- package/dist/types/components/general/schema-services.d.ts.map +1 -0
- package/dist/types/components/general/schema-website.d.ts.map +1 -0
- package/dist/types/components/general/sitemap.d.ts.map +1 -0
- package/dist/types/components/general/smartimage.d.ts.map +1 -0
- package/dist/types/components/general/socialcard.d.ts.map +1 -0
- package/dist/types/components/general/tiles.d.ts.map +1 -0
- package/dist/types/components/general/timeline.d.ts.map +1 -0
- package/dist/types/components/general/wordpress.components.d.ts.map +1 -0
- package/dist/types/components/general/wordpress.functions.d.ts.map +1 -0
- package/dist/types/components/general/yelp.d.ts.map +1 -0
- package/dist/types/components/sitebuilder/page/lib/componentMap.d.ts +1 -1
- package/dist/types/components/sitebuilder/page/lib/pageStorageContentful.d.ts +1 -1
- package/dist/types/components/sitebuilder/page/lib/pageStorageContentful.d.ts.map +1 -1
- package/dist/types/index.adminclient.d.ts +1 -0
- package/dist/types/index.adminserver.d.ts +1 -1
- package/dist/types/index.d.ts +48 -48
- package/dist/types/index.server.d.ts +19 -19
- package/dist/types/mocks/browser.d.ts +1 -0
- package/dist/types/mocks/browser.d.ts.map +1 -0
- package/dist/types/mocks/handlers.d.ts +2 -0
- package/dist/types/mocks/handlers.d.ts.map +1 -0
- package/dist/types/mocks/index.d.ts +1 -0
- package/dist/types/mocks/index.d.ts.map +1 -0
- package/dist/types/scripts/generate-site-images.d.ts +2 -0
- package/dist/types/scripts/generate-site-images.d.ts.map +1 -0
- package/dist/types/scripts/proptypes-inferprops.d.ts +28 -0
- package/dist/types/scripts/proptypes-inferprops.d.ts.map +1 -0
- package/dist/types/scripts/validate-exports.d.ts +2 -0
- package/dist/types/scripts/validate-exports.d.ts.map +1 -0
- package/dist/types/stories/admin/site-health.mocks.d.ts +82 -0
- package/dist/types/stories/admin/site-health.mocks.d.ts.map +1 -0
- package/dist/types/stories/admin/site-health.stories.d.ts.map +1 -1
- package/dist/types/stories/callout/callout.stories.d.ts +1 -1
- package/dist/types/stories/carousel/carousel-hero.stories.d.ts +1 -1
- package/dist/types/stories/carousel/carousel-hero.stories.d.ts.map +1 -1
- package/dist/types/stories/carousel/carousel-reviews.stories.d.ts +1 -1
- package/dist/types/stories/carousel/carousel-reviews.stories.d.ts.map +1 -1
- package/dist/types/stories/carousel/carousel-workportfolio.stories.d.ts +1 -1
- package/dist/types/stories/carousel/carousel-workportfolio.stories.d.ts.map +1 -1
- package/dist/types/stories/carousel/carousel.stories.d.ts +1 -1
- package/dist/types/stories/carousel/carousel.stories.d.ts.map +1 -1
- package/dist/types/stories/carousel/tiles.stories.d.ts +1 -1
- package/dist/types/stories/carousel/tiles.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/contentful.item.stories.d.ts +1 -1
- package/dist/types/stories/cms/contentful.item.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/contentful.items.stories.d.ts +1 -1
- package/dist/types/stories/cms/contentful.items.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/contentful.stories.d.ts +1 -1
- package/dist/types/stories/cms/contentful.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/google.reviews.stories.d.ts +1 -1
- package/dist/types/stories/cms/google.reviews.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/gravatar.stories.d.ts +1 -1
- package/dist/types/stories/cms/gravatar.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/instagram.stories.d.ts +1 -1
- package/dist/types/stories/cms/instagram.stories.d.ts.map +1 -1
- package/dist/types/stories/cms/wordpress.stories.d.ts +1 -1
- package/dist/types/stories/cms/wordpress.stories.d.ts.map +1 -1
- package/dist/types/stories/general/smartimage.stories.d.ts +1 -1
- package/dist/types/stories/general/smartimage.stories.d.ts.map +1 -1
- package/dist/types/stories/menu/menu-accordion.stories.d.ts +1 -1
- package/dist/types/stories/menu/menu-accordion.stories.d.ts.map +1 -1
- package/dist/types/stories/menu/menu-expando.stories.d.ts +1 -1
- package/dist/types/stories/menu/menu-expando.stories.d.ts.map +1 -1
- package/dist/types/stories/menu/menu-simple.stories.d.ts +1 -1
- package/dist/types/stories/menu/menu-simple.stories.d.ts.map +1 -1
- package/dist/types/stories/nerdjoke.stories.d.ts +1 -1
- package/dist/types/stories/nerdjoke.stories.d.ts.map +1 -1
- package/dist/types/stories/seo/seo.404.stories.d.ts +1 -1
- package/dist/types/stories/seo/seo.404.stories.d.ts.map +1 -1
- package/dist/types/stories/seo/seo.faq-accordion.stories.d.ts +1 -1
- package/dist/types/stories/seo/seo.faq-accordion.stories.d.ts.map +1 -1
- package/dist/types/stories/seo/seo.googleanalytics.stories.d.ts +1 -1
- package/dist/types/stories/seo/seo.googleanalytics.stories.d.ts.map +1 -1
- package/dist/types/stories/seo/seo.googlesearch.stories.d.ts +1 -1
- package/dist/types/stories/seo/seo.googlesearch.stories.d.ts.map +1 -1
- package/dist/types/stories/seo/seo.metadata.stories.d.ts +1 -1
- package/dist/types/stories/seo/seo.metadata.stories.d.ts.map +1 -1
- package/dist/types/stories/seo/seo.schema.stories.d.ts +1 -1
- package/dist/types/stories/seo/seo.schema.stories.d.ts.map +1 -1
- package/dist/types/stories/seo/seo.sitemap.stories.d.ts +1 -1
- package/dist/types/stories/seo/seo.sitemap.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/buzzword-bingo.stories.d.ts +2 -2
- package/dist/types/stories/structured/buzzword-bingo.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/markdown.stories.d.ts +1 -1
- package/dist/types/stories/structured/markdown.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/recipe.stories.d.ts +1 -1
- package/dist/types/stories/structured/recipe.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/resume.stories.d.ts +1 -1
- package/dist/types/stories/structured/resume.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/socialcard.stories.d.ts +1 -1
- package/dist/types/stories/structured/socialcard.stories.d.ts.map +1 -1
- package/dist/types/stories/structured/timeline.stories.d.ts +1 -1
- package/dist/types/stories/structured/timeline.stories.d.ts.map +1 -1
- package/package.json +16 -10
- package/dist/types/components/carousel/carousel.d.ts.map +0 -1
- package/dist/types/components/carousel/carousel.drag.d.ts.map +0 -1
- package/dist/types/components/carousel/tiles.d.ts.map +0 -1
- package/dist/types/components/cms/calendly.d.ts.map +0 -1
- package/dist/types/components/cms/cloudinary.d.ts.map +0 -1
- package/dist/types/components/cms/contentful.delivery.d.ts.map +0 -1
- package/dist/types/components/cms/contentful.items.components.d.ts.map +0 -1
- package/dist/types/components/cms/contentful.management.d.ts.map +0 -1
- package/dist/types/components/cms/flickr.d.ts.map +0 -1
- package/dist/types/components/cms/google.reviews.components.d.ts.map +0 -1
- package/dist/types/components/cms/google.reviews.functions.d.ts.map +0 -1
- package/dist/types/components/cms/gravatar.components.d.ts.map +0 -1
- package/dist/types/components/cms/gravatar.functions.d.ts.map +0 -1
- package/dist/types/components/cms/hubspot.components.d.ts.map +0 -1
- package/dist/types/components/cms/instagram.components.d.ts.map +0 -1
- package/dist/types/components/cms/instagram.functions.d.ts.map +0 -1
- package/dist/types/components/cms/smartimage.d.ts.map +0 -1
- package/dist/types/components/cms/wordpress.components.d.ts.map +0 -1
- package/dist/types/components/cms/wordpress.functions.d.ts.map +0 -1
- package/dist/types/components/cms/yelp.d.ts.map +0 -1
- package/dist/types/components/menu/menu-accordion.d.ts.map +0 -1
- package/dist/types/components/menu/menu-expando.d.ts.map +0 -1
- package/dist/types/components/menu/menu-simple.d.ts.map +0 -1
- package/dist/types/components/nerdjoke/nerdjoke.d.ts.map +0 -1
- package/dist/types/components/seo/404.d.ts.map +0 -1
- package/dist/types/components/seo/faq-accordion.d.ts.map +0 -1
- package/dist/types/components/seo/googleanalytics.d.ts.map +0 -1
- package/dist/types/components/seo/googlemap.d.ts.map +0 -1
- package/dist/types/components/seo/googlesearch.d.ts.map +0 -1
- package/dist/types/components/seo/manifest.d.ts.map +0 -1
- package/dist/types/components/seo/metadata.components.d.ts.map +0 -1
- package/dist/types/components/seo/metadata.functions.d.ts.map +0 -1
- package/dist/types/components/seo/schema-blogposting.d.ts.map +0 -1
- package/dist/types/components/seo/schema-blogposting.functions.d.ts.map +0 -1
- package/dist/types/components/seo/schema-faq.d.ts.map +0 -1
- package/dist/types/components/seo/schema-localbusiness.d.ts.map +0 -1
- package/dist/types/components/seo/schema-recipe.d.ts.map +0 -1
- package/dist/types/components/seo/schema-services.d.ts.map +0 -1
- package/dist/types/components/seo/schema-website.d.ts.map +0 -1
- package/dist/types/components/seo/sitemap.d.ts.map +0 -1
- package/dist/types/components/structured/buzzwordbingo.d.ts.map +0 -1
- package/dist/types/components/structured/buzzwordbingo.words.d.ts.map +0 -1
- package/dist/types/components/structured/markdown.d.ts.map +0 -1
- package/dist/types/components/structured/recipe.d.ts.map +0 -1
- package/dist/types/components/structured/resume.d.ts.map +0 -1
- package/dist/types/components/structured/socialcard.d.ts.map +0 -1
- package/dist/types/components/structured/timeline.d.ts.map +0 -1
- /package/dist/components/{seo → general}/404.css +0 -0
- /package/dist/components/{structured → general}/buzzwordbingo.css +0 -0
- /package/dist/components/{structured → general}/buzzwordbingo.js +0 -0
- /package/dist/components/{structured → general}/buzzwordbingo.words.js +0 -0
- /package/dist/components/{cms → general}/calendly.js +0 -0
- /package/dist/components/{callout → general}/callout.scss +0 -0
- /package/dist/components/{carousel → general}/carousel.css +0 -0
- /package/dist/components/{carousel → general}/carousel.drag.js +0 -0
- /package/dist/components/{cms → general}/cloudinary.js +0 -0
- /package/dist/components/{cms → general}/contentful.delivery.js +0 -0
- /package/dist/components/{cms → general}/contentful.items.css +0 -0
- /package/dist/components/{cms → general}/contentful.management.js +0 -0
- /package/dist/components/{seo → general}/faq-accordion.css +0 -0
- /package/dist/components/{seo → general}/faq-accordion.js +0 -0
- /package/dist/components/{cms → general}/flickr.js +0 -0
- /package/dist/components/{cms → general}/google.reviews.components.js +0 -0
- /package/dist/components/{cms → general}/google.reviews.css +0 -0
- /package/dist/components/{cms → general}/google.reviews.functions.js +0 -0
- /package/dist/components/{seo → general}/googleanalytics.js +0 -0
- /package/dist/components/{seo → general}/googlemap.js +0 -0
- /package/dist/components/{seo → general}/googlesearch.css +0 -0
- /package/dist/components/{seo → general}/googlesearch.js +0 -0
- /package/dist/components/{cms → general}/gravatar.css +0 -0
- /package/dist/components/{cms → general}/gravatar.functions.js +0 -0
- /package/dist/components/{cms → general}/hubspot.components.js +0 -0
- /package/dist/components/{cms → general}/instagram.functions.js +0 -0
- /package/dist/components/{seo → general}/manifest.js +0 -0
- /package/dist/components/{structured → general}/markdown.css +0 -0
- /package/dist/components/{menu → general}/menu-accordion.css +0 -0
- /package/dist/components/{menu → general}/menu-accordion.js +0 -0
- /package/dist/components/{menu → general}/menu-expando.css +0 -0
- /package/dist/components/{menu → general}/menu-expando.js +0 -0
- /package/dist/components/{menu → general}/menu-simple.css +0 -0
- /package/dist/components/{menu → general}/menu-simple.js +0 -0
- /package/dist/components/{seo → general}/metadata.components.js +0 -0
- /package/dist/components/{seo → general}/metadata.functions.js +0 -0
- /package/dist/components/{nerdjoke → general}/nerdjoke.css +0 -0
- /package/dist/components/{nerdjoke → general}/nerdjoke.js +0 -0
- /package/dist/components/{structured → general}/recipe.css +0 -0
- /package/dist/components/{structured → general}/resume.css +0 -0
- /package/dist/components/{seo → general}/schema-blogposting.functions.js +0 -0
- /package/dist/components/{seo → general}/schema-blogposting.js +0 -0
- /package/dist/components/{seo → general}/schema-faq.js +0 -0
- /package/dist/components/{seo → general}/schema-localbusiness.js +0 -0
- /package/dist/components/{seo → general}/schema-recipe.js +0 -0
- /package/dist/components/{seo → general}/schema-services.js +0 -0
- /package/dist/components/{seo → general}/schema-website.js +0 -0
- /package/dist/components/{structured → general}/socialcard.css +0 -0
- /package/dist/components/{carousel → general}/tiles.css +0 -0
- /package/dist/components/{structured → general}/timeline.css +0 -0
- /package/dist/components/{cms → general}/wordpress.css +0 -0
- /package/dist/components/{cms → general}/wordpress.functions.js +0 -0
- /package/dist/components/{cms → general}/yelp.js +0 -0
- /package/dist/types/components/{seo → general}/404.d.ts +0 -0
- /package/dist/types/components/{structured → general}/buzzwordbingo.d.ts +0 -0
- /package/dist/types/components/{structured → general}/buzzwordbingo.words.d.ts +0 -0
- /package/dist/types/components/{cms → general}/calendly.d.ts +0 -0
- /package/dist/types/components/{callout → general}/callout.d.ts +0 -0
- /package/dist/types/components/{carousel → general}/carousel.d.ts +0 -0
- /package/dist/types/components/{carousel → general}/carousel.drag.d.ts +0 -0
- /package/dist/types/components/{cms → general}/cloudinary.d.ts +0 -0
- /package/dist/types/components/{cms → general}/contentful.delivery.d.ts +0 -0
- /package/dist/types/components/{cms → general}/contentful.items.components.d.ts +0 -0
- /package/dist/types/components/{cms → general}/contentful.management.d.ts +0 -0
- /package/dist/types/components/{seo → general}/faq-accordion.d.ts +0 -0
- /package/dist/types/components/{cms → general}/google.reviews.components.d.ts +0 -0
- /package/dist/types/components/{cms → general}/google.reviews.functions.d.ts +0 -0
- /package/dist/types/components/{seo → general}/googleanalytics.d.ts +0 -0
- /package/dist/types/components/{seo → general}/googlemap.d.ts +0 -0
- /package/dist/types/components/{seo → general}/googlesearch.d.ts +0 -0
- /package/dist/types/components/{cms → general}/gravatar.components.d.ts +0 -0
- /package/dist/types/components/{cms → general}/gravatar.functions.d.ts +0 -0
- /package/dist/types/components/{cms → general}/hubspot.components.d.ts +0 -0
- /package/dist/types/components/{cms → general}/instagram.components.d.ts +0 -0
- /package/dist/types/components/{seo → general}/manifest.d.ts +0 -0
- /package/dist/types/components/{structured → general}/markdown.d.ts +0 -0
- /package/dist/types/components/{menu → general}/menu-accordion.d.ts +0 -0
- /package/dist/types/components/{menu → general}/menu-expando.d.ts +0 -0
- /package/dist/types/components/{menu → general}/menu-simple.d.ts +0 -0
- /package/dist/types/components/{seo → general}/metadata.components.d.ts +0 -0
- /package/dist/types/components/{seo → general}/metadata.functions.d.ts +0 -0
- /package/dist/types/components/{nerdjoke → general}/nerdjoke.d.ts +0 -0
- /package/dist/types/components/{structured → general}/recipe.d.ts +0 -0
- /package/dist/types/components/{structured → general}/resume.d.ts +0 -0
- /package/dist/types/components/{seo → general}/schema-blogposting.d.ts +0 -0
- /package/dist/types/components/{seo → general}/schema-faq.d.ts +0 -0
- /package/dist/types/components/{seo → general}/schema-localbusiness.d.ts +0 -0
- /package/dist/types/components/{seo → general}/schema-recipe.d.ts +0 -0
- /package/dist/types/components/{seo → general}/schema-services.d.ts +0 -0
- /package/dist/types/components/{seo → general}/schema-website.d.ts +0 -0
- /package/dist/types/components/{seo → general}/sitemap.d.ts +0 -0
- /package/dist/types/components/{cms → general}/smartimage.d.ts +0 -0
- /package/dist/types/components/{structured → general}/socialcard.d.ts +0 -0
- /package/dist/types/components/{carousel → general}/tiles.d.ts +0 -0
- /package/dist/types/components/{structured → general}/timeline.d.ts +0 -0
- /package/dist/types/components/{cms → general}/wordpress.components.d.ts +0 -0
- /package/dist/types/components/{cms → general}/wordpress.functions.d.ts +0 -0
- /package/dist/types/components/{cms → general}/yelp.d.ts +0 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { http, HttpResponse } from 'msw';
|
|
2
|
+
console.log('MSW handlers loaded');
|
|
3
|
+
// Mock data for Axe Core accessibility
|
|
4
|
+
const mockAxeData = {
|
|
5
|
+
success: true,
|
|
6
|
+
data: {
|
|
7
|
+
site: 'example.com',
|
|
8
|
+
url: 'https://example.com',
|
|
9
|
+
violations: [
|
|
10
|
+
{
|
|
11
|
+
id: 'color-contrast',
|
|
12
|
+
impact: 'serious',
|
|
13
|
+
description: 'Elements must have sufficient color contrast',
|
|
14
|
+
help: 'Ensure text has enough contrast against background',
|
|
15
|
+
helpUrl: 'https://dequeuniversity.com/rules/axe/4.8/color-contrast',
|
|
16
|
+
nodes: [
|
|
17
|
+
{
|
|
18
|
+
target: ['.header h1'],
|
|
19
|
+
html: '<h1>Welcome</h1>',
|
|
20
|
+
failureSummary: 'Fix any of the following: Element has insufficient color contrast of 2.5:1'
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: 'image-alt',
|
|
26
|
+
impact: 'critical',
|
|
27
|
+
description: 'Images must have alternate text',
|
|
28
|
+
help: 'Provide alternative text for images',
|
|
29
|
+
helpUrl: 'https://dequeuniversity.com/rules/axe/4.8/image-alt',
|
|
30
|
+
nodes: [
|
|
31
|
+
{
|
|
32
|
+
target: ['img[alt=""]'],
|
|
33
|
+
html: '<img src="logo.png" alt="">',
|
|
34
|
+
failureSummary: 'Fix any of the following: aria-label attribute does not exist or is empty'
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
],
|
|
39
|
+
passes: 45,
|
|
40
|
+
incomplete: 2,
|
|
41
|
+
inapplicable: 12
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
// Mock data for Core Web Vitals
|
|
45
|
+
const mockCoreWebVitalsData = {
|
|
46
|
+
success: true,
|
|
47
|
+
data: {
|
|
48
|
+
site: 'pixelated.tech',
|
|
49
|
+
url: 'https://pixelated.tech',
|
|
50
|
+
metrics: {
|
|
51
|
+
cls: 0.05,
|
|
52
|
+
fid: 85,
|
|
53
|
+
lcp: 1200,
|
|
54
|
+
fcp: 800,
|
|
55
|
+
ttfb: 150,
|
|
56
|
+
speedIndex: 1100,
|
|
57
|
+
interactive: 1300,
|
|
58
|
+
totalBlockingTime: 50,
|
|
59
|
+
firstMeaningfulPaint: 900
|
|
60
|
+
},
|
|
61
|
+
scores: {
|
|
62
|
+
performance: 85,
|
|
63
|
+
accessibility: 90,
|
|
64
|
+
bestPractices: 95,
|
|
65
|
+
seo: 88,
|
|
66
|
+
pwa: 75
|
|
67
|
+
},
|
|
68
|
+
categories: {
|
|
69
|
+
performance: { score: 85, displayValue: 'Good' },
|
|
70
|
+
accessibility: { score: 90, displayValue: 'Good' },
|
|
71
|
+
bestPractices: { score: 95, displayValue: 'Good' },
|
|
72
|
+
seo: { score: 88, displayValue: 'Good' },
|
|
73
|
+
pwa: { score: 75, displayValue: 'Good' }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
// Mock data for Google Analytics
|
|
78
|
+
const mockGoogleAnalyticsData = {
|
|
79
|
+
success: true,
|
|
80
|
+
data: {
|
|
81
|
+
site: 'pixelated.tech',
|
|
82
|
+
dateRange: {
|
|
83
|
+
start: '2024-01-01',
|
|
84
|
+
end: '2024-01-06'
|
|
85
|
+
},
|
|
86
|
+
metrics: {
|
|
87
|
+
users: 1250,
|
|
88
|
+
sessions: 1800,
|
|
89
|
+
pageviews: 3200,
|
|
90
|
+
bounceRate: 0.45,
|
|
91
|
+
avgSessionDuration: 180,
|
|
92
|
+
newUsers: 890
|
|
93
|
+
},
|
|
94
|
+
chartData: [
|
|
95
|
+
{ date: '2024-01-01', users: 120, sessions: 150, pageviews: 280 },
|
|
96
|
+
{ date: '2024-01-02', users: 135, sessions: 165, pageviews: 310 },
|
|
97
|
+
{ date: '2024-01-03', users: 142, sessions: 178, pageviews: 325 },
|
|
98
|
+
{ date: '2024-01-04', users: 158, sessions: 192, pageviews: 345 },
|
|
99
|
+
{ date: '2024-01-05', users: 165, sessions: 198, pageviews: 365 },
|
|
100
|
+
{ date: '2024-01-06', users: 172, sessions: 205, pageviews: 380 }
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
// Mock data for Google Search Console
|
|
105
|
+
const mockGoogleSearchConsoleData = {
|
|
106
|
+
success: true,
|
|
107
|
+
data: {
|
|
108
|
+
site: 'pixelated.tech',
|
|
109
|
+
dateRange: {
|
|
110
|
+
start: '2024-01-01',
|
|
111
|
+
end: '2024-01-06'
|
|
112
|
+
},
|
|
113
|
+
metrics: {
|
|
114
|
+
clicks: 1250,
|
|
115
|
+
impressions: 15000,
|
|
116
|
+
ctr: 0.083,
|
|
117
|
+
position: 12.5
|
|
118
|
+
},
|
|
119
|
+
chartData: [
|
|
120
|
+
{ date: '2024-01-01', clicks: 85, impressions: 1200, ctr: 0.071, position: 14.2 },
|
|
121
|
+
{ date: '2024-01-02', clicks: 92, impressions: 1350, ctr: 0.068, position: 13.8 },
|
|
122
|
+
{ date: '2024-01-03', clicks: 98, impressions: 1420, ctr: 0.069, position: 13.5 },
|
|
123
|
+
{ date: '2024-01-04', clicks: 105, impressions: 1480, ctr: 0.071, position: 13.2 },
|
|
124
|
+
{ date: '2024-01-05', clicks: 112, impressions: 1520, ctr: 0.074, position: 12.8 },
|
|
125
|
+
{ date: '2024-01-06', clicks: 118, impressions: 1580, ctr: 0.075, position: 12.5 }
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
// Mock data for CloudWatch uptime
|
|
130
|
+
const mockCloudWatchData = {
|
|
131
|
+
success: true,
|
|
132
|
+
data: {
|
|
133
|
+
site: 'pixelated.tech',
|
|
134
|
+
uptime: 99.8,
|
|
135
|
+
responseTime: 245,
|
|
136
|
+
status: 'operational',
|
|
137
|
+
incidents: [],
|
|
138
|
+
chartData: [
|
|
139
|
+
{ timestamp: '2024-01-01T00:00:00Z', uptime: 100, responseTime: 220 },
|
|
140
|
+
{ timestamp: '2024-01-02T00:00:00Z', uptime: 99.5, responseTime: 280 },
|
|
141
|
+
{ timestamp: '2024-01-03T00:00:00Z', uptime: 100, responseTime: 210 },
|
|
142
|
+
{ timestamp: '2024-01-04T00:00:00Z', uptime: 100, responseTime: 235 },
|
|
143
|
+
{ timestamp: '2024-01-05T00:00:00Z', uptime: 99.9, responseTime: 250 },
|
|
144
|
+
{ timestamp: '2024-01-06T00:00:00Z', uptime: 100, responseTime: 225 }
|
|
145
|
+
]
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
export const handlers = [
|
|
149
|
+
// API endpoints using relative paths (MSW v2 matches these regardless of origin)
|
|
150
|
+
http.get('/api/site-health/axe-core', () => {
|
|
151
|
+
console.log('MSW: Intercepting axe-core request');
|
|
152
|
+
return HttpResponse.json(mockAxeData);
|
|
153
|
+
}),
|
|
154
|
+
http.get('/api/site-health/core-web-vitals', () => {
|
|
155
|
+
console.log('MSW: Intercepting core-web-vitals request');
|
|
156
|
+
return HttpResponse.json(mockCoreWebVitalsData);
|
|
157
|
+
}),
|
|
158
|
+
http.get('/api/site-health/google-analytics', () => {
|
|
159
|
+
console.log('MSW: Intercepting google-analytics request');
|
|
160
|
+
return HttpResponse.json(mockGoogleAnalyticsData);
|
|
161
|
+
}),
|
|
162
|
+
http.get('/api/site-health/google-search-console', () => {
|
|
163
|
+
console.log('MSW: Intercepting google-search-console request');
|
|
164
|
+
return HttpResponse.json(mockGoogleSearchConsoleData);
|
|
165
|
+
}),
|
|
166
|
+
http.get('/api/site-health/cloudwatch', () => {
|
|
167
|
+
console.log('MSW: Intercepting cloudwatch request');
|
|
168
|
+
return HttpResponse.json(mockCloudWatchData);
|
|
169
|
+
}),
|
|
170
|
+
// External URLs used by some stories
|
|
171
|
+
http.get('https://api.pixelated.tech/axe-core', () => {
|
|
172
|
+
console.log('MSW: Intercepting external axe-core request');
|
|
173
|
+
return HttpResponse.json(mockAxeData);
|
|
174
|
+
}),
|
|
175
|
+
http.get('https://api.pixelated.tech/core-web-vitals', () => {
|
|
176
|
+
console.log('MSW: Intercepting external core-web-vitals request');
|
|
177
|
+
return HttpResponse.json(mockCoreWebVitalsData);
|
|
178
|
+
}),
|
|
179
|
+
http.get('https://api.pixelated.tech/google-analytics', () => {
|
|
180
|
+
console.log('MSW: Intercepting external google-analytics request');
|
|
181
|
+
return HttpResponse.json(mockGoogleAnalyticsData);
|
|
182
|
+
}),
|
|
183
|
+
http.get('https://api.pixelated.tech/google-search-console', () => {
|
|
184
|
+
console.log('MSW: Intercepting external google-search-console request');
|
|
185
|
+
return HttpResponse.json(mockGoogleSearchConsoleData);
|
|
186
|
+
}),
|
|
187
|
+
http.get('https://api.pixelated.tech/cloudwatch', () => {
|
|
188
|
+
console.log('MSW: Intercepting external cloudwatch request');
|
|
189
|
+
return HttpResponse.json(mockCloudWatchData);
|
|
190
|
+
}),
|
|
191
|
+
http.get('https://api.pixelated.tech/template-data', () => {
|
|
192
|
+
console.log('MSW: Intercepting template-data request');
|
|
193
|
+
return HttpResponse.json({
|
|
194
|
+
success: true,
|
|
195
|
+
data: { message: 'Mock template data' }
|
|
196
|
+
});
|
|
197
|
+
}),
|
|
198
|
+
// Generic fallback for any other site health endpoints
|
|
199
|
+
http.get('/api/site-health/*', () => {
|
|
200
|
+
console.log('MSW: Intercepting generic site-health request');
|
|
201
|
+
return HttpResponse.json({
|
|
202
|
+
success: true,
|
|
203
|
+
data: { message: 'Mock data for site health endpoint' }
|
|
204
|
+
});
|
|
205
|
+
})
|
|
206
|
+
];
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-require-imports */
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
const publicDir = path.join(__dirname, '..', 'public');
|
|
6
|
+
const outFile = path.join(publicDir, 'site-images.json');
|
|
7
|
+
|
|
8
|
+
function listFiles(dir, exts = ['.jpg','.jpeg','.png','.webp','.avif','.gif']) {
|
|
9
|
+
const out = [];
|
|
10
|
+
if (!fs.existsSync(dir)) return out;
|
|
11
|
+
const items = fs.readdirSync(dir, { withFileTypes: true });
|
|
12
|
+
for (const it of items) {
|
|
13
|
+
const full = path.join(dir, it.name);
|
|
14
|
+
if (it.isDirectory()) out.push(...listFiles(full, exts));
|
|
15
|
+
else if (exts.includes(path.extname(it.name).toLowerCase())) {
|
|
16
|
+
out.push(path.relative(publicDir, full).replace(/\\\\/g, '/'));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return out;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const files = listFiles(publicDir);
|
|
23
|
+
const manifest = {
|
|
24
|
+
metadata: {
|
|
25
|
+
generatedAt: new Date().toISOString(),
|
|
26
|
+
imageCount: files.length,
|
|
27
|
+
},
|
|
28
|
+
images: files,
|
|
29
|
+
};
|
|
30
|
+
fs.writeFileSync(outFile, JSON.stringify(manifest, null, 2), 'utf8');
|
|
31
|
+
console.log('Wrote', outFile, 'with', files.length, 'images and metadata');
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { isClientComponent } from '../components/utilities/functions.ts';
|
|
2
|
+
|
|
3
|
+
export default {
|
|
4
|
+
meta: {
|
|
5
|
+
type: 'problem',
|
|
6
|
+
docs: {
|
|
7
|
+
description: 'Enforce PropTypes + InferProps pattern for React components',
|
|
8
|
+
category: 'Best Practices',
|
|
9
|
+
recommended: true,
|
|
10
|
+
},
|
|
11
|
+
fixable: false,
|
|
12
|
+
schema: [],
|
|
13
|
+
messages: {
|
|
14
|
+
missingPropTypes: 'Component "{{componentName}}" is missing propTypes. Add: {{componentName}}.propTypes = { ... }; immediately above the function.',
|
|
15
|
+
missingInferProps: 'Component "{{componentName}}" is missing InferProps type. Add: export type {{componentName}}Type = InferProps<typeof {{componentName}}.propTypes>; immediately above the function.',
|
|
16
|
+
invalidInferProps: 'InferProps type for "{{componentName}}" must be named "{{componentName}}Type" and exported. Rename and add export.',
|
|
17
|
+
missingInferPropsUsage: 'Component "{{componentName}}" function parameters must use the InferProps type. Change: export function {{componentName}}(props: {{componentName}}Type)',
|
|
18
|
+
propTypesPlacement: 'Component "{{componentName}}" propTypes must be defined immediately above the function declaration with no blank lines. Move {{componentName}}.propTypes = { ... }; right above the function.',
|
|
19
|
+
inferPropsPlacement: 'Component "{{componentName}}" InferProps type must be defined immediately above the function declaration with no blank lines. Move export type {{componentName}}Type = ...; right above the function.',
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
create(context) {
|
|
23
|
+
|
|
24
|
+
const components = new Map(); // Track components and their patterns
|
|
25
|
+
|
|
26
|
+
function checkForInferProps(typeAnnotation) {
|
|
27
|
+
if (!typeAnnotation) return false;
|
|
28
|
+
|
|
29
|
+
if (typeAnnotation.type === 'TSTypeReference' && typeAnnotation.typeName?.name === 'InferProps') {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (typeAnnotation.type === 'TSIntersectionType') {
|
|
34
|
+
return typeAnnotation.types.some(checkForInferProps);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function extractComponentNameFromInferProps(node) {
|
|
41
|
+
// For our pattern of ComponentType = InferProps<typeof Component.propTypes>
|
|
42
|
+
// We can simply remove 'Type' from the type name
|
|
43
|
+
return node.id.name.replace('Type', '');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function reportViolations(component) {
|
|
47
|
+
const { functionNode, hasPropTypes, hasInferProps, usesInferProps, inferPropsName, propTypesNode, inferPropsNode } = component;
|
|
48
|
+
if (!functionNode) return; // Skip if function not found yet
|
|
49
|
+
|
|
50
|
+
const componentName = functionNode.id.name;
|
|
51
|
+
|
|
52
|
+
if (!hasPropTypes) {
|
|
53
|
+
context.report({
|
|
54
|
+
node: functionNode,
|
|
55
|
+
messageId: 'missingPropTypes',
|
|
56
|
+
data: { componentName },
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (!hasInferProps) {
|
|
61
|
+
context.report({
|
|
62
|
+
node: functionNode,
|
|
63
|
+
messageId: 'missingInferProps',
|
|
64
|
+
data: { componentName },
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (hasPropTypes && hasInferProps && !usesInferProps && functionNode.params.length > 0) {
|
|
69
|
+
context.report({
|
|
70
|
+
node: functionNode,
|
|
71
|
+
messageId: 'missingInferPropsUsage',
|
|
72
|
+
data: { componentName, inferPropsName },
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Check placement and ordering: propTypes -> InferProps -> function (consecutive, no empty lines)
|
|
77
|
+
if (hasPropTypes && hasInferProps && propTypesNode && inferPropsNode) {
|
|
78
|
+
const propTypesEndLine = propTypesNode.loc.end.line;
|
|
79
|
+
const inferPropsLine = inferPropsNode.loc.start.line;
|
|
80
|
+
const functionLine = functionNode.loc.start.line;
|
|
81
|
+
|
|
82
|
+
// InferProps must immediately follow propTypes (no empty lines)
|
|
83
|
+
if (inferPropsLine !== propTypesEndLine + 1) {
|
|
84
|
+
context.report({
|
|
85
|
+
node: inferPropsNode,
|
|
86
|
+
messageId: 'inferPropsPlacement',
|
|
87
|
+
data: { componentName },
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// Function must immediately follow InferProps (no empty lines)
|
|
92
|
+
if (functionLine !== inferPropsLine + 1) {
|
|
93
|
+
context.report({
|
|
94
|
+
node: functionNode,
|
|
95
|
+
messageId: 'propTypesPlacement',
|
|
96
|
+
data: { componentName },
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return {
|
|
103
|
+
// Find component function declarations
|
|
104
|
+
FunctionDeclaration(node) {
|
|
105
|
+
if (node.id && node.id.name && node.parent.type === 'ExportNamedDeclaration') {
|
|
106
|
+
const componentName = node.id.name;
|
|
107
|
+
|
|
108
|
+
// Check if this is a client component (contains client-only patterns)
|
|
109
|
+
const sourceCode = context.getSourceCode();
|
|
110
|
+
const fileContent = sourceCode.text;
|
|
111
|
+
if (componentName[0] === componentName[0].toUpperCase() && isClientComponent(fileContent)) {
|
|
112
|
+
if (!components.has(componentName)) {
|
|
113
|
+
components.set(componentName, {
|
|
114
|
+
functionNode: node,
|
|
115
|
+
hasPropTypes: false,
|
|
116
|
+
hasInferProps: false,
|
|
117
|
+
inferPropsName: `${componentName}Type`,
|
|
118
|
+
usesInferProps: false,
|
|
119
|
+
propTypesNode: null,
|
|
120
|
+
inferPropsNode: null,
|
|
121
|
+
});
|
|
122
|
+
} else {
|
|
123
|
+
// Component entry already exists (e.g., from propTypes), just update functionNode
|
|
124
|
+
components.get(componentName).functionNode = node;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
|
|
130
|
+
// Find PropTypes assignments
|
|
131
|
+
AssignmentExpression(node) {
|
|
132
|
+
if (
|
|
133
|
+
node.left.type === 'MemberExpression' &&
|
|
134
|
+
node.left.object.type === 'Identifier' &&
|
|
135
|
+
node.left.property.name === 'propTypes'
|
|
136
|
+
) {
|
|
137
|
+
const componentName = node.left.object.name;
|
|
138
|
+
if (!components.has(componentName)) {
|
|
139
|
+
// Component might be declared later, create entry now
|
|
140
|
+
components.set(componentName, {
|
|
141
|
+
functionNode: null, // Will be set when function is found
|
|
142
|
+
hasPropTypes: false,
|
|
143
|
+
hasInferProps: false,
|
|
144
|
+
inferPropsName: `${componentName}Type`,
|
|
145
|
+
usesInferProps: false,
|
|
146
|
+
propTypesNode: null,
|
|
147
|
+
inferPropsNode: null,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
const component = components.get(componentName);
|
|
151
|
+
component.hasPropTypes = true;
|
|
152
|
+
component.propTypesNode = node;
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
// Find InferProps type declarations
|
|
157
|
+
TSTypeAliasDeclaration(node) {
|
|
158
|
+
if (node.parent.type === 'ExportNamedDeclaration') {
|
|
159
|
+
const componentName = extractComponentNameFromInferProps(node);
|
|
160
|
+
if (componentName && components.has(componentName)) {
|
|
161
|
+
const component = components.get(componentName);
|
|
162
|
+
if (node.id.name === component.inferPropsName) {
|
|
163
|
+
// Check if type annotation contains InferProps
|
|
164
|
+
const hasInferProps = checkForInferProps(node.typeAnnotation);
|
|
165
|
+
if (hasInferProps) {
|
|
166
|
+
component.hasInferProps = true;
|
|
167
|
+
component.inferPropsNode = node;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
// Check function parameters
|
|
175
|
+
'FunctionDeclaration:exit'(node) {
|
|
176
|
+
if (node.id && components.has(node.id.name)) {
|
|
177
|
+
const component = components.get(node.id.name);
|
|
178
|
+
|
|
179
|
+
// Check if function uses the InferProps type
|
|
180
|
+
if (node.params.length === 1) {
|
|
181
|
+
const param = node.params[0];
|
|
182
|
+
|
|
183
|
+
// Handle both direct type annotation and destructured parameters
|
|
184
|
+
let paramTypeName = null;
|
|
185
|
+
|
|
186
|
+
if (param.type === 'Identifier' && param.typeAnnotation?.typeAnnotation?.type === 'TSTypeReference') {
|
|
187
|
+
// Direct parameter: (props: ComponentType)
|
|
188
|
+
paramTypeName = param.typeAnnotation.typeAnnotation.typeName?.name;
|
|
189
|
+
} else if (param.type === 'ObjectPattern' && param.typeAnnotation?.typeAnnotation?.type === 'TSTypeReference') {
|
|
190
|
+
// Destructured parameter: ({ prop }: ComponentType)
|
|
191
|
+
paramTypeName = param.typeAnnotation.typeAnnotation.typeName?.name;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (paramTypeName === component.inferPropsName) {
|
|
195
|
+
component.usesInferProps = true;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Report violations
|
|
200
|
+
reportViolations(component);
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
};
|
|
204
|
+
},
|
|
205
|
+
};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
# Universal Release Script for Pixelated Projects
|
|
4
|
+
# This script builds in dev, updates main, and optionally publishes to npm
|
|
5
|
+
|
|
6
|
+
set -e # Exit on any error
|
|
7
|
+
|
|
8
|
+
# Get project name from package.json
|
|
9
|
+
PROJECT_NAME=$(node -p "require('./package.json').name" 2>/dev/null || echo "unknown-project")
|
|
10
|
+
|
|
11
|
+
# Function to prompt for remote selection
|
|
12
|
+
prompt_remote_selection() {
|
|
13
|
+
echo "Available git remotes:" >&2
|
|
14
|
+
local remotes=($(git remote))
|
|
15
|
+
local i=1
|
|
16
|
+
for remote in "${remotes[@]}"; do
|
|
17
|
+
echo "$i) $remote" >&2
|
|
18
|
+
((i++))
|
|
19
|
+
done
|
|
20
|
+
|
|
21
|
+
local choice
|
|
22
|
+
read -p "Select remote to use (1-${#remotes[@]}): " choice >&2
|
|
23
|
+
|
|
24
|
+
case $choice in
|
|
25
|
+
[1-9]|[1-9][0-9])
|
|
26
|
+
if [ "$choice" -le "${#remotes[@]}" ]; then
|
|
27
|
+
echo "${remotes[$((choice-1))]}"
|
|
28
|
+
else
|
|
29
|
+
echo "${remotes[0]}" # Default to first if invalid
|
|
30
|
+
fi
|
|
31
|
+
;;
|
|
32
|
+
*) echo "${remotes[0]}" ;; # Default to first remote
|
|
33
|
+
esac
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
# Select remote
|
|
37
|
+
REMOTE_NAME=$(prompt_remote_selection)
|
|
38
|
+
|
|
39
|
+
echo "🚀 Starting Release Process for $PROJECT_NAME"
|
|
40
|
+
echo "================================================="
|
|
41
|
+
|
|
42
|
+
# Function to get current version
|
|
43
|
+
get_current_version() {
|
|
44
|
+
node -p "require('./package.json').version"
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
# Function to prompt for version bump type
|
|
48
|
+
prompt_version_type() {
|
|
49
|
+
echo "Current version: $(get_current_version)" >&2
|
|
50
|
+
echo "Select version bump type:" >&2
|
|
51
|
+
echo "1) patch (x.x.1)" >&2
|
|
52
|
+
echo "2) minor (x.1.0)" >&2
|
|
53
|
+
echo "3) major (1.x.x)" >&2
|
|
54
|
+
echo "4) custom version" >&2
|
|
55
|
+
echo "5) no version bump" >&2
|
|
56
|
+
read -p "Enter choice (1-5): " choice >&2
|
|
57
|
+
case $choice in
|
|
58
|
+
1) version_type="patch" ;;
|
|
59
|
+
2) version_type="minor" ;;
|
|
60
|
+
3) version_type="major" ;;
|
|
61
|
+
4)
|
|
62
|
+
read -p "Enter custom version: " custom_version >&2
|
|
63
|
+
version_type="$custom_version"
|
|
64
|
+
;;
|
|
65
|
+
5) version_type="none" ;;
|
|
66
|
+
*) version_type="patch" ;; # default
|
|
67
|
+
esac
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
# Function to prompt for commit message
|
|
71
|
+
prompt_commit_message() {
|
|
72
|
+
read -p "Enter commit message (or press enter for default): " commit_msg
|
|
73
|
+
if [ -z "$commit_msg" ]; then
|
|
74
|
+
echo "chore: release $(get_current_version)"
|
|
75
|
+
else
|
|
76
|
+
echo "$commit_msg"
|
|
77
|
+
fi
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
# Function to prompt for publishing
|
|
81
|
+
prompt_publish() {
|
|
82
|
+
read -p "Do you want to publish to npm? (y/n): " should_publish
|
|
83
|
+
if [ "$should_publish" = "y" ] || [ "$should_publish" = "Y" ]; then
|
|
84
|
+
echo "yes"
|
|
85
|
+
else
|
|
86
|
+
echo "no"
|
|
87
|
+
fi
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# Function to prompt for OTP
|
|
91
|
+
prompt_otp() {
|
|
92
|
+
read -p "Enter npm OTP: " otp
|
|
93
|
+
echo "$otp"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# Check if we're on dev branch
|
|
97
|
+
current_branch=$(git branch --show-current)
|
|
98
|
+
if [ "$current_branch" != "dev" ]; then
|
|
99
|
+
echo "❌ Error: Must be on dev branch to run this script"
|
|
100
|
+
echo "Current branch: $current_branch"
|
|
101
|
+
echo "Please switch to dev branch: git checkout dev"
|
|
102
|
+
exit 1
|
|
103
|
+
fi
|
|
104
|
+
|
|
105
|
+
echo "📦 Step 1: Updating dependencies..."
|
|
106
|
+
npm outdated | awk 'NR>1 {print $1"@"$4}' | xargs npm install --force --save 2>/dev/null || true
|
|
107
|
+
npm audit fix --force 2>/dev/null || true
|
|
108
|
+
|
|
109
|
+
echo "🔍 Step 2: Running lint..."
|
|
110
|
+
npm run lint
|
|
111
|
+
|
|
112
|
+
echo "🔨 Step 3: Building project..."
|
|
113
|
+
npm run build
|
|
114
|
+
|
|
115
|
+
echo "🏷️ Step 4: Version bump..."
|
|
116
|
+
prompt_version_type
|
|
117
|
+
if [ "$version_type" != "none" ]; then
|
|
118
|
+
if [ "$version_type" = "patch" ] || [ "$version_type" = "minor" ] || [ "$version_type" = "major" ]; then
|
|
119
|
+
npm version $version_type --force --no-git-tag-version
|
|
120
|
+
else
|
|
121
|
+
# Custom version
|
|
122
|
+
npm version $version_type --force --no-git-tag-version
|
|
123
|
+
fi
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
echo "💾 Step 5: Committing changes..."
|
|
127
|
+
commit_message=$(prompt_commit_message)
|
|
128
|
+
git add . -v
|
|
129
|
+
if git diff --cached --quiet; then
|
|
130
|
+
echo "ℹ️ No changes to commit"
|
|
131
|
+
else
|
|
132
|
+
git commit -m "$commit_message"
|
|
133
|
+
fi
|
|
134
|
+
|
|
135
|
+
echo "📤 Step 6: Pushing dev branch..."
|
|
136
|
+
# Try to push, if it fails due to remote changes, fetch and rebase
|
|
137
|
+
if ! git push $REMOTE_NAME dev; then
|
|
138
|
+
echo "⚠️ Push failed, fetching remote changes and rebasing..."
|
|
139
|
+
git fetch $REMOTE_NAME
|
|
140
|
+
if git rebase $REMOTE_NAME/dev; then
|
|
141
|
+
echo "✅ Rebased successfully, pushing..."
|
|
142
|
+
git push $REMOTE_NAME dev || {
|
|
143
|
+
echo "❌ Failed to push after rebase. Please check git status."
|
|
144
|
+
exit 1
|
|
145
|
+
}
|
|
146
|
+
else
|
|
147
|
+
echo "❌ Rebase failed. Please resolve conflicts and run 'git rebase --continue' or 'git rebase --abort'"
|
|
148
|
+
exit 1
|
|
149
|
+
fi
|
|
150
|
+
fi
|
|
151
|
+
|
|
152
|
+
echo "🔄 Step 7: Updating main branch..."
|
|
153
|
+
# Force main to match dev exactly
|
|
154
|
+
git push $REMOTE_NAME dev:main --force
|
|
155
|
+
|
|
156
|
+
# Also update main locally if it exists
|
|
157
|
+
if git show-ref --verify --quiet refs/heads/main; then
|
|
158
|
+
git branch -D main 2>/dev/null || true
|
|
159
|
+
git checkout -b main
|
|
160
|
+
git reset --hard dev
|
|
161
|
+
git push $REMOTE_NAME main --force
|
|
162
|
+
git checkout dev
|
|
163
|
+
fi
|
|
164
|
+
|
|
165
|
+
echo "🏷️ Step 8: Creating and pushing git tag..."
|
|
166
|
+
new_version=$(get_current_version)
|
|
167
|
+
if ! git tag -l | grep -q "v$new_version"; then
|
|
168
|
+
git tag "v$new_version"
|
|
169
|
+
git push $REMOTE_NAME "v$new_version"
|
|
170
|
+
else
|
|
171
|
+
echo "ℹ️ Tag v$new_version already exists"
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
echo "🔐 Step 9: Publishing to npm..."
|
|
175
|
+
should_publish=$(prompt_publish)
|
|
176
|
+
if [ "$should_publish" = "yes" ]; then
|
|
177
|
+
npm login
|
|
178
|
+
otp=$(prompt_otp)
|
|
179
|
+
npm publish --access public --otp=$otp
|
|
180
|
+
echo "✅ Successfully published to npm!"
|
|
181
|
+
else
|
|
182
|
+
echo "ℹ️ Skipping npm publish"
|
|
183
|
+
echo "You can publish manually with: npm publish --access public"
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
echo ""
|
|
187
|
+
echo "✅ Release complete!"
|
|
188
|
+
echo "📦 Version: $(get_current_version)"
|
|
189
|
+
echo "📋 Branches updated: dev, main"
|
|
190
|
+
echo "🏷️ Tag created: v$(get_current_version)"
|
|
191
|
+
|
|
192
|
+
if [ "$should_publish" = "yes" ]; then
|
|
193
|
+
echo "🔗 https://www.npmjs.com/package/$PROJECT_NAME"
|
|
194
|
+
fi
|