sourcebit-sample-plugin
Advanced tools
Comparing version 0.3.0 to 0.3.1
288
index.js
@@ -1,3 +0,3 @@ | ||
const axios = require("axios"); | ||
const pkg = require("./package.json"); | ||
const axios = require('axios'); | ||
const pkg = require('./package.json'); | ||
@@ -39,25 +39,25 @@ /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | ||
module.exports.options = { | ||
mySecret: { | ||
// 👉 The value will be read from `process.env.MY_SECRET`. | ||
env: "MY_SECRET", | ||
mySecret: { | ||
// 👉 The value will be read from `process.env.MY_SECRET`. | ||
env: 'MY_SECRET', | ||
// 👉 When running the interactive setup process, this | ||
// option will be stored in an `.env` file instead of the | ||
// main configuration file. | ||
private: true | ||
}, | ||
watch: { | ||
// 👉 By default, the value of this option will be `false`. | ||
default: false, | ||
// 👉 When running the interactive setup process, this | ||
// option will be stored in an `.env` file instead of the | ||
// main configuration file. | ||
private: true | ||
}, | ||
watch: { | ||
// 👉 By default, the value of this option will be `false`. | ||
default: false, | ||
// 👉 The value for this option will be read from the `watch` | ||
// runtime parameter, which means that if the user starts | ||
// Sourcebit with `sourcebit fetch --watch`, then the value | ||
// of this option will be set to `true`, regardless of any | ||
// other value defined in the configuration file. | ||
runtimeParameter: "watch" | ||
}, | ||
titleCase: { | ||
default: false | ||
} | ||
// 👉 The value for this option will be read from the `watch` | ||
// runtime parameter, which means that if the user starts | ||
// Sourcebit with `sourcebit fetch --watch`, then the value | ||
// of this option will be set to `true`, regardless of any | ||
// other value defined in the configuration file. | ||
runtimeParameter: 'watch' | ||
}, | ||
titleCase: { | ||
default: false | ||
} | ||
}; | ||
@@ -93,59 +93,50 @@ | ||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
module.exports.bootstrap = async ({ | ||
debug, | ||
getPluginContext, | ||
log, | ||
options, | ||
refresh, | ||
setPluginContext | ||
}) => { | ||
// 👉 Get the plugin's context object. This is useful for the | ||
// plugin to share any data between its various methods during | ||
// its runtime lifecycle. | ||
// Additionally, it leverages Sourcebit's caching layer, which | ||
// means that whatever a plugin stores in its context will be | ||
// persisted to disk and loaded automatically on the next run. | ||
const context = getPluginContext(); | ||
module.exports.bootstrap = async ({ debug, getPluginContext, log, options, refresh, setPluginContext }) => { | ||
// 👉 Get the plugin's context object. This is useful for the | ||
// plugin to share any data between its various methods during | ||
// its runtime lifecycle. | ||
// Additionally, it leverages Sourcebit's caching layer, which | ||
// means that whatever a plugin stores in its context will be | ||
// persisted to disk and loaded automatically on the next run. | ||
const context = getPluginContext(); | ||
// 👉 If there are entries in the cache, there's nothing that | ||
// needs to be done right now. | ||
if (context && context.entries) { | ||
log(`Loaded ${context.entries.length} entries from cache`); | ||
} else { | ||
const { data: entries } = await axios.get( | ||
"https://jsonplaceholder.typicode.com/posts" | ||
); | ||
// 👉 If there are entries in the cache, there's nothing that | ||
// needs to be done right now. | ||
if (context && context.entries) { | ||
log(`Loaded ${context.entries.length} entries from cache`); | ||
} else { | ||
const { data: entries } = await axios.get('https://jsonplaceholder.typicode.com/posts'); | ||
log(`Loaded ${entries.length} entries`); | ||
debug("Initial entries: %O", entries); | ||
log(`Loaded ${entries.length} entries`); | ||
debug('Initial entries: %O', entries); | ||
// 👉 Adding the newly-generated entries to the plugin's | ||
// context object. | ||
setPluginContext({ | ||
entries | ||
}); | ||
} | ||
// 👉 Adding the newly-generated entries to the plugin's | ||
// context object. | ||
setPluginContext({ | ||
entries | ||
}); | ||
} | ||
// 👉 If the `watch` option is enabled, we set up a polling routine | ||
// that checks for changes in the data source. In a real-world plugin, | ||
// you'd be doing things like making regular calls to an API to check | ||
// whenever something changes. | ||
if (options.watch) { | ||
setInterval(() => { | ||
const { entries } = getPluginContext(); | ||
const entryIndex = Math.floor(Math.random() * entries.length); | ||
// 👉 If the `watch` option is enabled, we set up a polling routine | ||
// that checks for changes in the data source. In a real-world plugin, | ||
// you'd be doing things like making regular calls to an API to check | ||
// whenever something changes. | ||
if (options.watch) { | ||
setInterval(() => { | ||
const { entries } = getPluginContext(); | ||
const entryIndex = Math.floor(Math.random() * entries.length); | ||
entries[entryIndex].body = entries[entryIndex].body + " (updated)"; | ||
entries[entryIndex].body = entries[entryIndex].body + ' (updated)'; | ||
log(`Updated entry #${entryIndex}`); | ||
debug("Updated entries: %O", entries); | ||
log(`Updated entry #${entryIndex}`); | ||
debug('Updated entries: %O', entries); | ||
// 👉 We take the new entries array and update the plugin context. | ||
setPluginContext({ entries }); | ||
// 👉 We take the new entries array and update the plugin context. | ||
setPluginContext({ entries }); | ||
// 👉 After updating the context, we must communicate the change and | ||
// the need for all plugins to re-run in order to act on the new data. | ||
refresh(); | ||
}, 3000); | ||
} | ||
// 👉 After updating the context, we must communicate the change and | ||
// the need for all plugins to re-run in order to act on the new data. | ||
refresh(); | ||
}, 3000); | ||
} | ||
}; | ||
@@ -185,50 +176,44 @@ | ||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
module.exports.transform = ({ | ||
data, | ||
debug, | ||
getPluginContext, | ||
log, | ||
options | ||
}) => { | ||
// 👉 Let's retrieve from the plugin's context object the | ||
// entries that we've created in the bootstrap method. | ||
const { entries } = getPluginContext(); | ||
module.exports.transform = ({ data, debug, getPluginContext, log, options }) => { | ||
// 👉 Let's retrieve from the plugin's context object the | ||
// entries that we've created in the bootstrap method. | ||
const { entries } = getPluginContext(); | ||
// Source plugins are encouraged to add information about their | ||
// models to the `models` data bucket. | ||
const model = { | ||
source: pkg.name, | ||
modelName: "sample-data", | ||
modelLabel: "Mock data", | ||
projectId: "12345", | ||
projectEnvironment: "master", | ||
fieldNames: ["firstName", "lastName", "points"] | ||
}; | ||
// Source plugins are encouraged to add information about their | ||
// models to the `models` data bucket. | ||
const model = { | ||
source: pkg.name, | ||
modelName: 'sample-data', | ||
modelLabel: 'Mock data', | ||
projectId: '12345', | ||
projectEnvironment: 'master', | ||
fieldNames: ['userId', 'id', 'title', 'body'] | ||
}; | ||
// 👉 The main purpose of this method is to normalize the | ||
// entries, so that they conform to a standardized format | ||
// used by all source plugins. | ||
const normalizedEntries = entries.map(entry => { | ||
const title = options.titleCase | ||
? entry.title | ||
.split(" ") | ||
.map(word => word[0].toUpperCase() + word.substring(1)) | ||
.join(" ") | ||
: entry.title; | ||
// 👉 The main purpose of this method is to normalize the | ||
// entries, so that they conform to a standardized format | ||
// used by all source plugins. | ||
const normalizedEntries = entries.map(entry => { | ||
const title = options.titleCase | ||
? entry.title | ||
.split(' ') | ||
.map(word => word[0].toUpperCase() + word.substring(1)) | ||
.join(' ') | ||
: entry.title; | ||
return { | ||
...entry, | ||
title, | ||
__metadata: model | ||
}; | ||
}); | ||
// 👉 The method must return the updated data object, which | ||
// in our case means appending our entries to the `objects` | ||
// property. | ||
return { | ||
...entry, | ||
title, | ||
__metadata: model | ||
...data, | ||
models: data.models.concat(model), | ||
objects: data.objects.concat(normalizedEntries) | ||
}; | ||
}); | ||
// 👉 The method must return the updated data object, which | ||
// in our case means appending our entries to the `objects` | ||
// property. | ||
return { | ||
...data, | ||
models: data.models.concat(model), | ||
objects: data.objects.concat(normalizedEntries) | ||
}; | ||
}; | ||
@@ -275,39 +260,29 @@ | ||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
module.exports.getSetup = ({ | ||
chalk, | ||
context, | ||
currentOptions, | ||
data, | ||
debug, | ||
getSetupContext, | ||
inquirer, | ||
ora, | ||
setSetupContext | ||
}) => { | ||
const questions = [ | ||
{ | ||
type: "confirm", | ||
name: "titleCase", | ||
message: "Do you want to convert the title field to title-case?", | ||
default: currentOptions.pointsForJane || false | ||
} | ||
]; | ||
module.exports.getSetup = ({ chalk, context, currentOptions, data, debug, getSetupContext, inquirer, ora, setSetupContext }) => { | ||
const questions = [ | ||
{ | ||
type: 'confirm', | ||
name: 'titleCase', | ||
message: 'Do you want to convert the title field to title-case?', | ||
default: currentOptions.pointsForJane || false | ||
} | ||
]; | ||
// 👉 For simple setup processes, this method can simply return | ||
// an array of questions in the format expected by `inquirer`. | ||
// Alternatively, it can run its own setup instance, display | ||
// messages, make external calls, etc. For this, it should return | ||
// a function which, when executed, must return a Promise with | ||
// an answers object. | ||
return async () => { | ||
const spinner = ora("Crunching some numbers...").start(); | ||
// 👉 For simple setup processes, this method can simply return | ||
// an array of questions in the format expected by `inquirer`. | ||
// Alternatively, it can run its own setup instance, display | ||
// messages, make external calls, etc. For this, it should return | ||
// a function which, when executed, must return a Promise with | ||
// an answers object. | ||
return async () => { | ||
const spinner = ora('Crunching some numbers...').start(); | ||
// ⏳ await runSomeAsyncTask(); | ||
// ⏳ await runSomeAsyncTask(); | ||
spinner.succeed(); | ||
spinner.succeed(); | ||
const answers = await inquirer.prompt(questions); | ||
const answers = await inquirer.prompt(questions); | ||
return answers; | ||
}; | ||
return answers; | ||
}; | ||
}; | ||
@@ -343,14 +318,9 @@ | ||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | ||
module.exports.getOptionsFromSetup = ({ | ||
answers, | ||
debug, | ||
getSetupContext, | ||
setSetupContext | ||
}) => { | ||
// 👉 This is a good place to make some transformation to the | ||
// values generated in the setup process before they're added | ||
// to the configuration file. | ||
return { | ||
titleCase: answers.titleCase | ||
}; | ||
module.exports.getOptionsFromSetup = ({ answers, debug, getSetupContext, setSetupContext }) => { | ||
// 👉 This is a good place to make some transformation to the | ||
// values generated in the setup process before they're added | ||
// to the configuration file. | ||
return { | ||
titleCase: answers.titleCase | ||
}; | ||
}; |
{ | ||
"name": "sourcebit-sample-plugin", | ||
"version": "0.3.0", | ||
"version": "0.3.1", | ||
"description": "A sample Sourcebit plugin", | ||
@@ -8,3 +8,6 @@ "main": "index.js", | ||
"test": "npm run format", | ||
"format": "prettier --write \"./**/*.{js,jsx,md,html}\"" | ||
"format": "prettier --write \"./**/*.{js,jsx,md,html}\"", | ||
"prepack": "npm test", | ||
"version-minor": "npm version minor -m \"bumped version to v%s\"", | ||
"version-patch": "npm version patch -m \"bumped version to v%s\"" | ||
}, | ||
@@ -28,2 +31,3 @@ "repository": { | ||
"devDependencies": { | ||
"@stackbit/prettier-config": "^1.0.0", | ||
"husky": "^4.0.0", | ||
@@ -46,3 +50,4 @@ "lint-staged": "^9.5.0", | ||
"axios": "^0.19.2" | ||
} | ||
}, | ||
"prettier": "@stackbit/prettier-config" | ||
} |
@@ -13,2 +13,4 @@ # sourcebit-sample-plugin | ||
**For a step-by-step walkthrough on building a Sourcebit plugin, check out our tutorial at: <https://www.stackbit.com/blog/sourcebit-plugin/>** | ||
## 🏗 Installation | ||
@@ -28,6 +30,6 @@ | ||
- In the `options` object of the plugin configuration block inside `sourcebit.js`, with the value of the _Property_ column as a key; | ||
- As an environment variable named after the _Env variable_ column, when running the `sourcebit fetch` command; | ||
- As part of a `.env` file, with the value of the _Env variable_ column separated by the value with an equals sign (e.g. `MY_VARIABLE=my-value`); | ||
- As a CLI parameter, when running the `sourcebit fetch` command, using the value of the _Parameter_ column as the name of the parameter (e.g. `sourcebit fetch --my-parameter`). | ||
- In the `options` object of the plugin configuration block inside `sourcebit.js`, with the value of the _Property_ column as a key; | ||
- As an environment variable named after the _Env variable_ column, when running the `sourcebit fetch` command; | ||
- As part of a `.env` file, with the value of the _Env variable_ column separated by the value with an equals sign (e.g. `MY_VARIABLE=my-value`); | ||
- As a CLI parameter, when running the `sourcebit fetch` command, using the value of the _Parameter_ column as the name of the parameter (e.g. `sourcebit fetch --my-parameter`). | ||
@@ -46,10 +48,10 @@ | Property | Type | Visibility | Default value | Env variable | Parameter | Description | | ||
module.exports = { | ||
plugins: [ | ||
{ | ||
module: require("sourcebit-sample-plugin"), | ||
options: { | ||
titleCase: true | ||
} | ||
} | ||
] | ||
plugins: [ | ||
{ | ||
module: require('sourcebit-sample-plugin'), | ||
options: { | ||
titleCase: true | ||
} | ||
} | ||
] | ||
}; | ||
@@ -56,0 +58,0 @@ ``` |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
27485
9
85
4
296
1