diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index b40545160..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - env: { - node: true, - commonjs: true, - es2021: true, - }, - extends: 'eslint:recommended', - ignorePatterns: ['tests/*'], - parserOptions: { - ecmaVersion: 12, - sourceType: 'module', - }, - rules: {}, -}; diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..cb7ca4c7b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +version: 2 +updates: + - package-ecosystem: "npm" + directory: "/" + schedule: + interval: "daily" + time: "05:00" + commit-message: + prefix: fix + prefix-development: chore + include: scope diff --git a/.github/workflows/dependabot-automerge.yml b/.github/workflows/dependabot-automerge.yml new file mode 100644 index 000000000..b3b01e7e0 --- /dev/null +++ b/.github/workflows/dependabot-automerge.yml @@ -0,0 +1,28 @@ +# **** AUTOMERGE **** +# Merge automatically the PR that contain a minor or patch update on the dependency you define in env.DEPENDENCY +# - Inspiration: https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically/automating-dependabot-with-github-actions#enable-auto-merge-on-a-pull-request + +name: Dependabot auto-merge +on: pull_request + +permissions: + pull-requests: write + contents: write + +jobs: + dependabot: + runs-on: ubuntu-latest + if: ${{ github.actor == 'dependabot[bot]' }} + steps: + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v1.1.1 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + - name: Enable auto-merge for Dependabot PRs + if: ${{contains(steps.metadata.outputs.dependency-names, env.DEPENDENCY) && (steps.metadata.outputs.update-type == 'version-update:semver-patch' || steps.metadata.outputs.update-type == 'version-update:semver-minor')}} + run: gh pr merge --auto --merge "$PR_URL" + env: + DEPENDENCY: "@storyblok/react" + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..9de2da2ba --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,33 @@ +name: Release CI + +on: + push: + branches: [main, feature/v4] + pull_request: + branches: [main, feature/v4] + +jobs: + release: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Node + uses: actions/setup-node@v2 + with: + node-version: "16.13.2" + cache: "npm" + - name: Install dependencies + run: npm ci + - name: Build lib + run: npm run build + - name: Jest run + run: npm run test:unit + - name: Cypress run + run: npm run test:e2e + - name: Release + working-directory: lib + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} + run: npx semantic-release diff --git a/.gitignore b/.gitignore index 622bd7234..f2704de5a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ -node_modules -.cache/ .DS_Store -yarn-error.log -yarn.lock +node_modules +dist +dist-v2 +lib/cypress/videos +.next \ No newline at end of file diff --git a/.husky/.gitignore b/.husky/.gitignore new file mode 100644 index 000000000..31354ec13 --- /dev/null +++ b/.husky/.gitignore @@ -0,0 +1 @@ +_ diff --git a/.husky/commit-msg b/.husky/commit-msg new file mode 100644 index 000000000..2b0b740ca --- /dev/null +++ b/.husky/commit-msg @@ -0,0 +1,6 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx --no -- commitlint --edit "$1" +# npx --no-install commitlint --edit + diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 000000000..36af21989 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npx lint-staged diff --git a/.npmignore b/.npmignore new file mode 100644 index 000000000..728a19f85 --- /dev/null +++ b/.npmignore @@ -0,0 +1,4 @@ +.* +*.md +*.json +example \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js deleted file mode 100644 index d05636081..000000000 --- a/.prettierrc.js +++ /dev/null @@ -1,7 +0,0 @@ -module.exports = { - endOfLine: 'lf', - semi: true, - singleQuote: true, - tabWidth: 2, - printWidth: 100, -}; diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 555597fda..000000000 --- a/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - 12 -after_success: - - npx semantic-release@17 \ No newline at end of file diff --git a/README.md b/README.md index be830b367..1b83b3ba2 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ export const query = graphql` #### 2. Listen to Storyblok Visual Editor events -Use `useStoryblok` to get the new story every time is triggered a `change` event from the Visual Editor. You need to pass the `originalStory` as a first param. `bridgeOptions` (second param) is an optional param if you want to set the options for bridge by yourself: +Use `useStoryblokState` to get the new story every time is triggered a `change` event from the Visual Editor. You need to pass the `originalStory` as a first param. `bridgeOptions` (second param) is an optional param if you want to set the options for bridge by yourself: ```js import { StoryblokComponent, useStoryblokState } from "gatsby-source-storyblok" @@ -190,11 +190,9 @@ import { storyblokEditable } from "gatsby-source-storyblok"; const Feature = ({ blok }) => { return ( -
-
-
{blok.name}
-

{blok.description}

-
+
+
{blok.name}
+

{blok.description}

); }; diff --git a/gatsby-node.js b/gatsby-node.js deleted file mode 100644 index bbd04b993..000000000 --- a/gatsby-node.js +++ /dev/null @@ -1,145 +0,0 @@ -const StoryblokClient = require('storyblok-js-client'); -const Sync = require('./src/sync'); -const getStoryParams = require('./src/getStoryParams'); -const stringify = require('json-stringify-safe'); -const { createRemoteFileNode } = require(`gatsby-source-filesystem`); - -exports.sourceNodes = async function ({ actions }, options) { - const { createNode, setPluginStatus } = actions; - const client = new StoryblokClient(options); - - Sync.init({ - createNode, - setPluginStatus, - client, - }); - - const space = await Sync.getSpace(); - const languages = options.languages ? options.languages : space.language_codes; - languages.push(''); - - for (const language of languages) { - await Sync.getAll('stories', { - node: 'StoryblokEntry', - params: getStoryParams(language, options), - process: (item) => { - for (var prop in item.content) { - // eslint-disable-next-line no-prototype-builtins - if (!item.content.hasOwnProperty(prop) || ['_editable', '_uid'].indexOf(prop) > -1) { - continue; - } - const objectType = Object.prototype.toString - .call(item.content[prop]) - .replace('[object ', '') - .replace(']', '') - .toLowerCase(); - - if (['number', 'boolean', 'string'].indexOf(objectType) === -1) { - continue; - } - - const type = prop == 'component' ? '' : '_' + objectType; - - item['field_' + prop + type] = item.content[prop]; - } - - item.content = stringify(item.content); - }, - }); - } - - await Sync.getAll('tags', { - node: 'StoryblokTag', - params: getStoryParams('', options), - process: (item) => { - item.id = item.name; - }, - }); - - if (options.includeLinks === true) { - await Sync.getAll('links', { - node: 'StoryblokLink', - params: getStoryParams('', options), - }); - } - - const datasources = await Sync.getAll('datasources', { - node: 'StoryblokDatasource', - }); - - for (const datasource of datasources) { - const datasourceSlug = datasource.slug; - - await Sync.getAll('datasource_entries', { - node: 'StoryblokDatasourceEntry', - params: { - datasource: datasourceSlug, - }, - process: (item) => { - item.data_source_dimension = null; - item.data_source = datasourceSlug; - }, - }); - - const datasourceDimensions = datasource.dimensions || []; - - for (const dimension of datasourceDimensions) { - await Sync.getAll('datasource_entries', { - node: 'StoryblokDatasourceEntry', - params: { - datasource: datasourceSlug, - dimension: dimension.entry_value, - }, - process: (item) => { - item.data_source_dimension = dimension.entry_value; - item.data_source = datasourceSlug; - }, - }); - } - } -}; - -exports.onCreateNode = async ( - { node, actions: { createNode }, createNodeId, getCache, cache }, - options -) => { - if (!options.localAssets) { - return; - } - - if (node.internal.type === 'StoryblokEntry') { - const assetRegex = /(https:\/\/a\.storyblok\.com.+?(?:\.)(\w)*)/g; - let imagePaths = node.content.match(assetRegex); - if (imagePaths?.length) { - imagePaths.forEach(async (imagePath) => { - let fileNodeID; - - const mediaDataCacheKey = `sb-${imagePath}`; - const cacheMediaData = await getCache(mediaDataCacheKey); - const isCached = cacheMediaData && node.cv === cacheMediaData.updatedAt; - - if (isCached) { - fileNodeID = cacheMediaData.fileNodeID; - } - - if (!fileNodeID && imagePath) { - const fileNode = await createRemoteFileNode({ - url: imagePath, - parentNodeId: node.id, - createNode, - createNodeId, - getCache, - }); - - if (fileNode.id) { - fileNodeID = fileNode.id; - await cache.set(mediaDataCacheKey, { - fileNodeID, - updatedAt: node.cv, - }); - } - } - }); - } - } -}; diff --git a/index.js b/index.js deleted file mode 100644 index 625c0891b..000000000 --- a/index.js +++ /dev/null @@ -1 +0,0 @@ -// noop \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 111b76f65..f007311ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43395,4 +43395,4 @@ } } } -} \ No newline at end of file +} diff --git a/src/getStoryParams.js b/src/getStoryParams.js deleted file mode 100644 index e5f5f38c2..000000000 --- a/src/getStoryParams.js +++ /dev/null @@ -1,31 +0,0 @@ -/** - * @method getStoryParams - * @param {String} language 'en', 'de' - * @param {Object} options? api options - * @param {Array} options.resolveRelations? resolve_relations field - * @param {String} options.resolveLinks? can be story or url - * @param {String} options.version? can be draft or released - */ -const getStoryParams = function(language = '', options = {}) { - let params = {} - - if (options.resolveLinks) { - params.resolve_links = options.resolveLinks || '1' - } - - if (options.resolveRelations) { - params.resolve_relations = options.resolveRelations.join(',') - } - - if (options.version) { - params.version = options.version - } - - if (language.length > 0) { - params.language = language - } - - return params -} - -module.exports = getStoryParams \ No newline at end of file diff --git a/src/sync.js b/src/sync.js deleted file mode 100644 index 082f5fd31..000000000 --- a/src/sync.js +++ /dev/null @@ -1,104 +0,0 @@ -const crypto = require('crypto'); -const stringify = require('json-stringify-safe'); - -module.exports = { - init({ createNode, client, setPluginStatus }) { - setPluginStatus({ lastFetched: Date.now() }); - this.$createNode = createNode; - this.$client = client; - this.$cacheVersion = 0; - }, - - async getSpace() { - const space = await this.getOne('space', 'spaces/me', { - node: 'StoryblokSpace', - }); - this.$cacheVersion = space.version; - return space; - }, - - getPage(type, page, options) { - let params = { - per_page: 25, - page: page, - cv: this.$cacheVersion, - }; - params = Object.assign({}, params, options.params); - return this.$client.get(`cdn/${type}`, params); - }, - - createNode(name, item) { - const nodeObject = this.builderNode(name, item); - - this.$createNode(nodeObject); - }, - - builderNode(name, item) { - if (name === 'StoryblokDatasourceEntry') { - return this.factoryDatasourceEntryNode(name, item); - } - - return this.factoryDefaultNode(name, item); - }, - - factoryDefaultNode(name, item) { - const lang = item.lang || 'default'; - - return Object.assign({}, item, { - id: `${name.toLowerCase()}-${item.id}-${lang}`, - internalId: item.id, - parent: null, - children: [], - internal: { - type: name, - contentDigest: crypto.createHash(`md5`).update(stringify(item)).digest(`hex`), - }, - }); - }, - - factoryDatasourceEntryNode(name, item) { - const dimension = item.data_source_dimension || 'default'; - return Object.assign({}, item, { - id: `${name.toLowerCase()}-${item.id}-${dimension}`, - internalId: item.id, - parent: null, - children: [], - internal: { - type: name, - contentDigest: crypto.createHash(`md5`).update(stringify(item)).digest(`hex`), - }, - }); - }, - - async getOne(single, type, options) { - const resp = await this.$client.get(`cdn/${type}`, options.params); - const item = resp.data[single]; - this.createNode(options.node, item); - return item; - }, - - async getAll(type, options) { - let page = 1; - let res = await this.getPage(type, page, options); - let all = - res.data[type].constructor === Object ? Object.values(res.data[type]) : res.data[type]; - let lastPage = Math.ceil(res.total / 25); - - while (page < lastPage) { - page++; - res = await this.getPage(type, page, options); - res.data[type].forEach((item) => { - all.push(item); - }); - } - - all.forEach((item) => { - if (options.process) { - options.process(item); - } - this.createNode(options.node, item); - }); - - return all; - }, -}; diff --git a/tests/get-story-params.test.js b/tests/get-story-params.test.js deleted file mode 100644 index 6e557a730..000000000 --- a/tests/get-story-params.test.js +++ /dev/null @@ -1,49 +0,0 @@ -const getStoryParams = require('../src/getStoryParams') - -describe('getStoryParams() function', () => { - test('without any argument should be return a empty object', () => { - expect(getStoryParams()).toEqual({}) - }) - - test('with a language and story as resolveLinks option', () => { - const options = { - resolveLinks: 'story' - } - expect(getStoryParams('en', options)).toEqual({ - language: 'en', - resolve_links: 'story' - }) - }) - - test('with a language and url as resolveLinks option', () => { - const options = { - resolveLinks: 'url' - } - expect(getStoryParams('en', options)).toEqual({ - language: 'en', - resolve_links: 'url' - }) - }) - - test('with a language and version option', () => { - const options = { - version: 'draft' - } - expect(getStoryParams('en', options)).toEqual({ - language: 'en', - version: 'draft' - }) - }) - - test('with a language and version and resolve_relations options', () => { - const options = { - version: 'draft', - resolveRelations: ['page.author', 'page.categories'] - } - expect(getStoryParams('en', options)).toEqual({ - language: 'en', - version: 'draft', - resolve_relations: 'page.author,page.categories' - }) - }) -}) diff --git a/tests/sync.test.js b/tests/sync.test.js deleted file mode 100644 index 62080b776..000000000 --- a/tests/sync.test.js +++ /dev/null @@ -1,19 +0,0 @@ -const StoryblokClient = require('storyblok-js-client') -const Sync = require('../src/sync') - -test('horizontal_rule to generate hr tag', () => { - const createNode = function(node) { - expect(node.internalId).toBe(123) - expect(node.id).toBe(`item-123-default`) - } - const setPluginStatus = function() {} - const client = new StoryblokClient({}) - - Sync.init({ - createNode, - setPluginStatus, - client - }) - - Sync.createNode('Item', {id: 123}) -}) \ No newline at end of file