create-sails-generator 0.0.0 → 0.0.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # create-sails-generator: A Sails Generator for The Boring JavaScript Stack
2
2
 
3
- Welcome to the Create-Sails-Generator! This generator is specifically designed for The Boring JavaScript Stack, providing a plethora of CLI commands for code generation and more to expedite your development process with Sails.js.
3
+ This generator is specifically designed for The Boring JavaScript Stack, providing a plethora of commands for code generation and more to expedite your development process with The Boring JavaScript Stack.
4
4
 
5
5
  ## Features
6
6
 
@@ -0,0 +1,24 @@
1
+ const path = require('path')
2
+ /**
3
+ * Generates responses/badRequest.js file
4
+ */
5
+ module.exports = {
6
+ before: function (scope, done) {
7
+ if (scope.force !== false) {
8
+ scope.force = true
9
+ }
10
+ scope.relPath = 'badRequest.js'
11
+ return done()
12
+ },
13
+ after: function (scope, done) {
14
+ console.log()
15
+ console.log(`Successfully generated ${scope.relPath}`)
16
+ console.log(' •-', `api/responses/${scope.relPath}`)
17
+ console.log()
18
+ return done()
19
+ },
20
+ targets: {
21
+ './api/responses/:relPath': { copy: 'badRequest.js' }
22
+ },
23
+ templatesDirectory: path.resolve(__dirname, './templates')
24
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * badRequest.js
3
+ *
4
+ * A custom response.
5
+ *
6
+ * Example usage:
7
+ * ```
8
+ * return res.badRequest();
9
+ * // -or-
10
+ * return res.badRequest(optionalData);
11
+ * ```
12
+ *
13
+ * Or with actions2:
14
+ * ```
15
+ * exits: {
16
+ * somethingHappened: {
17
+ * responseType: 'badRequest'
18
+ * }
19
+ * }
20
+ * ```
21
+ *
22
+ * ```
23
+ * throw 'somethingHappened';
24
+ * // -or-
25
+ * throw { somethingHappened: optionalData }
26
+ * ```
27
+ */
28
+
29
+ module.exports = function badRequest(optionalData) {
30
+ // Get access to `req` and `res`
31
+ const req = this.req
32
+ const res = this.res
33
+
34
+ // Define the status code to send in the response.
35
+ const statusCodeToSet = 400
36
+
37
+ // Check if it's an Inertia request
38
+ if (req.header('X-Inertia')) {
39
+ if (optionalData && optionalData.problems) {
40
+ const errors = {}
41
+ optionalData.problems.forEach((problem) => {
42
+ if (typeof problem === 'object') {
43
+ Object.keys(problem).forEach((propertyName) => {
44
+ const sanitizedProblem = problem[propertyName].replace(/\.$/, '') // Trim trailing dot
45
+ if (!errors[propertyName]) {
46
+ errors[propertyName] = [sanitizedProblem]
47
+ } else {
48
+ errors[propertyName].push(sanitizedProblem)
49
+ }
50
+ })
51
+ } else {
52
+ const regex = /"(.*?)"/
53
+ const matches = problem.match(regex)
54
+
55
+ if (matches && matches.length > 1) {
56
+ const propertyName = matches[1]
57
+ const sanitizedProblem = problem
58
+ .replace(/"([^"]+)"/, '$1')
59
+ .replace('\n', '')
60
+ .replace('·', '')
61
+ .trim()
62
+ if (!errors[propertyName]) {
63
+ errors[propertyName] = [sanitizedProblem]
64
+ } else {
65
+ errors[propertyName].push(sanitizedProblem)
66
+ }
67
+ }
68
+ }
69
+ })
70
+ req.session.errors = errors
71
+ return res.redirect(303, 'back')
72
+ }
73
+ }
74
+
75
+ // If not an Inertia request, perform the normal badRequest response
76
+ if (optionalData === undefined) {
77
+ sails.log.info('Ran custom response: res.badRequest()')
78
+ return res.sendStatus(statusCodeToSet)
79
+ } else if (_.isError(optionalData)) {
80
+ sails.log.info(
81
+ 'Custom response `res.badRequest()` called with an Error:',
82
+ optionalData
83
+ )
84
+
85
+ if (!_.isFunction(optionalData.toJSON)) {
86
+ if (process.env.NODE_ENV === 'production') {
87
+ return res.sendStatus(statusCodeToSet)
88
+ } else {
89
+ return res.status(statusCodeToSet).send(optionalData.stack)
90
+ }
91
+ }
92
+ } else {
93
+ return res.status(statusCodeToSet).send(optionalData)
94
+ }
95
+ }
@@ -0,0 +1,24 @@
1
+ const path = require('path')
2
+ /**
3
+ * Generates responses/inertia.js file
4
+ */
5
+ module.exports = {
6
+ before: function (scope, done) {
7
+ if (scope.force !== false) {
8
+ scope.force = true
9
+ }
10
+ scope.relPath = 'inertia.js'
11
+ return done()
12
+ },
13
+ after: function (scope, done) {
14
+ console.log()
15
+ console.log(`Successfully generated ${scope.relPath}`)
16
+ console.log(' •-', `api/responses/${scope.relPath}`)
17
+ console.log()
18
+ return done()
19
+ },
20
+ targets: {
21
+ './api/responses/:relPath': { copy: 'inertia.js' }
22
+ },
23
+ templatesDirectory: path.resolve(__dirname, './templates')
24
+ }
@@ -0,0 +1,72 @@
1
+ // @ts-nocheck
2
+ const { encode } = require('querystring')
3
+ module.exports = function inertia(data) {
4
+ const req = this.req
5
+ const res = this.res
6
+ const sails = req._sails
7
+
8
+ const sharedProps = sails.inertia.sharedProps
9
+ const sharedViewData = sails.inertia.sharedViewData
10
+ const rootView = sails.config.inertia.rootView
11
+
12
+ const allProps = {
13
+ ...sharedProps,
14
+ ...data.props
15
+ }
16
+
17
+ const allViewData = {
18
+ ...sharedViewData,
19
+ ...data.viewData
20
+ }
21
+
22
+ let url = req.url || req.originalUrl
23
+ const assetVersion = sails.config.inertia.version
24
+ const currentVersion =
25
+ typeof assetVersion === 'function' ? assetVersion() : assetVersion
26
+
27
+ const page = {
28
+ component: data.page,
29
+ version: currentVersion,
30
+ props: allProps,
31
+ url
32
+ }
33
+
34
+ // Implements inertia partial reload. See https://inertiajs.com/partial-reload
35
+ if (
36
+ req.get(inertiaHeaders.PARTIAL_DATA) &&
37
+ req.get(inertiaHeaders.PARTIAL_COMPONENT) === page.component
38
+ ) {
39
+ const only = req.get(inertiaHeaders.PARTIAL_DATA).split(',')
40
+ page.props = only.length ? getPartialData(data.props, only) : page.props
41
+ }
42
+
43
+ const queryParams = req.query
44
+ if (req.method === 'GET' && Object.keys(queryParams).length) {
45
+ // Keep original request query params
46
+ url += `?${encode(queryParams)}`
47
+ }
48
+
49
+ if (req.get(inertiaHeaders.INERTIA)) {
50
+ res.set(inertiaHeaders.INERTIA, true)
51
+ res.set('Vary', 'Accept')
52
+ return res.json(page)
53
+ } else {
54
+ // Implements full page reload
55
+ return res.view(rootView, {
56
+ page,
57
+ viewData: allViewData
58
+ })
59
+ }
60
+ }
61
+
62
+ function getPartialData(props, only = []) {
63
+ return Object.assign({}, ...only.map((key) => ({ [key]: props[key] })))
64
+ }
65
+
66
+ const inertiaHeaders = {
67
+ INERTIA: 'X-Inertia',
68
+ VERSION: 'X-Inertia-Version',
69
+ PARTIAL_DATA: 'X-Inertia-Partial-Data',
70
+ PARTIAL_COMPONENT: 'X-Inertia-Partial-Component',
71
+ LOCATION: 'X-Inertia-Location'
72
+ }
@@ -0,0 +1,24 @@
1
+ const path = require('path')
2
+ /**
3
+ * Generates responses/inertia.js file
4
+ */
5
+ module.exports = {
6
+ before: function (scope, done) {
7
+ if (scope.force !== false) {
8
+ scope.force = true
9
+ }
10
+ scope.relPath = 'inertiaRedirect.js'
11
+ return done()
12
+ },
13
+ after: function (scope, done) {
14
+ console.log()
15
+ console.log(`Successfully generated ${scope.relPath}`)
16
+ console.log(' •-', `api/responses/${scope.relPath}`)
17
+ console.log()
18
+ return done()
19
+ },
20
+ targets: {
21
+ './api/responses/:relPath': { copy: 'inertiaRedirect.js' }
22
+ },
23
+ templatesDirectory: path.resolve(__dirname, './templates')
24
+ }
@@ -0,0 +1,20 @@
1
+ // @ts-nocheck
2
+
3
+ const inertiaHeaders = {
4
+ INERTIA: 'X-Inertia',
5
+ LOCATION: 'X-Inertia-Location'
6
+ }
7
+
8
+ module.exports = function inertiaRedirect(url) {
9
+ const req = this.req
10
+ const res = this.res
11
+
12
+ if (req.get(inertiaHeaders.INERTIA)) {
13
+ res.set(inertiaHeaders.LOCATION, url)
14
+ }
15
+
16
+ return res.redirect(
17
+ ['PUT', 'PATCH', 'DELETE'].includes(req.method) ? 303 : 409,
18
+ url
19
+ )
20
+ }
@@ -0,0 +1,70 @@
1
+ const path = require('path')
2
+ const getUiFramework = require('../../utils/get-ui-framework')
3
+ const getComponentName = require('../../utils/get-component-name')
4
+ const getFileExtensionForUi = require('../../utils/get-file-extension-for-ui')
5
+ const getActionName = require('../../utils/get-action-name')
6
+ /**
7
+ * Generates responses/inertia.js file
8
+ */
9
+
10
+ module.exports = {
11
+ before: function (scope, done) {
12
+ const appPackageJSON = require(`${scope.topLvlRootPath}/package.json`)
13
+ const uiFramework = getUiFramework(appPackageJSON)
14
+ let roughName
15
+
16
+ if (scope.name) {
17
+ roughName = scope.name
18
+ }
19
+
20
+ if (scope.args[0] && typeof scope.args[0] == 'string') {
21
+ roughName = scope.args[0]
22
+ }
23
+
24
+ if (!roughName) {
25
+ return done(
26
+ new Error(
27
+ 'Missing argument: Please provide a name for the new page.\n' +
28
+ '(e.g. `profile` or `sign-up`).'
29
+ )
30
+ )
31
+ }
32
+
33
+ // Replace backslashes with proper slashes.
34
+ // (This is crucial for Windows compatibility.)
35
+ roughName = roughName.replace(/\\/g, '/')
36
+
37
+ scope.pageRelPath = roughName.replace(/\.+/g, '/')
38
+ scope.pagePath = scope.pageRelPath
39
+ console.log(scope.pagePath)
40
+ scope.pageRelPath += getFileExtensionForUi(uiFramework)
41
+ scope.uiFramework = uiFramework
42
+ if (uiFramework == 'react') {
43
+ scope.componentName = getComponentName(roughName)
44
+ }
45
+
46
+ scope.actionRelPath = getActionName(roughName)
47
+ scope.actionRelPath += '.js'
48
+ scope.actionFriendlyName = `View ${scope.pagePath}`
49
+ scope.actionDescription = `Display ${scope.pagePath} page`
50
+
51
+ return done()
52
+ },
53
+ after: function (scope, done) {
54
+ console.log()
55
+
56
+ console.log(`Successfully generated ${scope.pageRelPath}`)
57
+ console.log(' •-', `assets/js/pages/${scope.pageRelPath}`)
58
+
59
+ console.log(`Successfully generated ${scope.actionRelPath}`)
60
+ console.log(' •-', `api/controllers/${scope.actionRelPath}`)
61
+
62
+ console.log()
63
+ return done()
64
+ },
65
+ targets: {
66
+ './assets/js/pages/:pageRelPath': { template: 'page.template' },
67
+ './api/controllers/:actionRelPath': { template: 'action.template' }
68
+ },
69
+ templatesDirectory: path.resolve(__dirname, './templates')
70
+ }
@@ -0,0 +1,15 @@
1
+ module.exports = {
2
+ friendlyName: <%= util.inspect(actionFriendlyName) %>,
3
+
4
+ description: <%= util.inspect(actionDescription) %>,
5
+
6
+ exits: {
7
+ success: {
8
+ responseType: 'inertia'
9
+ }
10
+ },
11
+
12
+ fn: async function () {
13
+ return { page: <%= util.inspect(pagePath) %> }
14
+ }
15
+ }
@@ -0,0 +1,19 @@
1
+ <% if (uiFramework == 'vue') {%>
2
+ <script setup>
3
+ import { Head, Link, useForm, usePage } from '@inertiajs/vue3'
4
+ </script>
5
+
6
+ <template></template>
7
+ <% } else if (uiFramework == 'react') { %>
8
+ import { Head, Link, useForm, usePage } from '@inertiajs/react'
9
+
10
+ export default function <%= componentName %>(props) {
11
+ return <div></div>
12
+ }
13
+ <% } else if (uiFramework == 'svelte') { %>
14
+ <script>
15
+ import { Link, useForm, page } from '@inertiajs/svelte'
16
+ </script>
17
+
18
+ <div></div>
19
+ <% } %>
package/index.js ADDED
File without changes
package/package.json CHANGED
@@ -1,12 +1,15 @@
1
1
  {
2
2
  "name": "create-sails-generator",
3
- "version": "0.0.0",
3
+ "version": "0.0.2",
4
4
  "description": "Sails generator for The Boring JavaScript Stack.",
5
- "main": "index.js",
6
5
  "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
6
+ "test": "node --test"
8
7
  },
9
- "keywords": ["The Boring JavaScript Stack", "sails", "senerator"],
8
+ "keywords": [
9
+ "The Boring JavaScript Stack",
10
+ "sails",
11
+ "senerator"
12
+ ],
10
13
  "author": "Kelvin Omereshone<kelvin@sailscasts.com>",
11
14
  "license": "MIT",
12
15
  "peerDependencies": {
@@ -0,0 +1,18 @@
1
+ const { describe, it } = require('node:test')
2
+ const assert = require('node:assert/strict')
3
+ const getActionName = require('../../utils/get-action-name')
4
+
5
+ describe('getActionName', function () {
6
+ it("returns 'view-dashboard' when given 'dashboard'", function () {
7
+ assert.equal(getActionName('dashboard'), 'view-dashboard')
8
+ })
9
+ it("returns 'user/view-users' when given 'users/index'", function () {
10
+ assert.equal(getActionName('users/index'), 'user/view-users')
11
+ })
12
+ it("returns 'user/view-user' when given 'users/user'", function () {
13
+ assert.equal(getActionName('users/user'), 'user/view-user')
14
+ })
15
+ it("returns 'user/view-profile' when given 'users/profile'", function () {
16
+ assert.equal(getActionName('users/profile'), 'user/view-profile')
17
+ })
18
+ })
@@ -0,0 +1,15 @@
1
+ const { describe, it } = require('node:test')
2
+ const assert = require('node:assert/strict')
3
+ const getComponentName = require('../../utils/get-component-name')
4
+
5
+ describe('getComponentName', function () {
6
+ it("returns 'Profile' when given 'profile'", function () {
7
+ assert.equal(getComponentName('profile'), 'Profile')
8
+ })
9
+ it("returns 'UserDashboard' when given 'user-dashboard'", function () {
10
+ assert.equal(getComponentName('user-dashboard'), 'UserDashboard')
11
+ })
12
+ it("returns 'ExampleNewPage' when given 'example/new-page'", function () {
13
+ assert.equal(getComponentName('example/new-page'), 'ExampleNewPage')
14
+ })
15
+ })
@@ -0,0 +1,15 @@
1
+ const { describe, it } = require('node:test')
2
+ const assert = require('node:assert/strict')
3
+ const getFileExtensionForUI = require('../../utils/get-file-extension-for-ui')
4
+
5
+ describe('getFileExtensionForUI', function () {
6
+ it("returns '.vue' when given 'vue'", function () {
7
+ assert.equal(getFileExtensionForUI('vue'), '.vue')
8
+ })
9
+ it("returns '.jsx' when given 'react'", function () {
10
+ assert.equal(getFileExtensionForUI('react'), '.jsx')
11
+ })
12
+ it("returns '.svelte' when given 'svelte'", function () {
13
+ assert.equal(getFileExtensionForUI('svelte'), '.svelte')
14
+ })
15
+ })
@@ -0,0 +1,9 @@
1
+ module.exports = function getActionName(pageName) {
2
+ if (!pageName.includes('/')) return `view-${pageName}`
3
+
4
+ const [firstPart, secondPart] = pageName.split('/')
5
+ const actionName =
6
+ secondPart === 'index' ? `view-${firstPart}` : `view-${secondPart}`
7
+
8
+ return `${firstPart.replace(/s$/, '')}/${actionName}`
9
+ }
@@ -0,0 +1,11 @@
1
+ module.exports = function getComponentName(str) {
2
+ const words = str.split(/-|\//)
3
+
4
+ return words
5
+ .map((word, index) =>
6
+ index === 0
7
+ ? word.charAt(0).toUpperCase() + word.slice(1)
8
+ : word.charAt(0).toUpperCase() + word.slice(1)
9
+ )
10
+ .join('')
11
+ }
@@ -0,0 +1,9 @@
1
+ module.exports = function getFileExtensionForUI(uiFramework) {
2
+ const extensions = {
3
+ vue: '.vue',
4
+ react: '.jsx',
5
+ svelte: '.svelte'
6
+ }
7
+
8
+ return extensions[uiFramework]
9
+ }
@@ -0,0 +1,13 @@
1
+ module.exports = function getUIFramework(packageJSON) {
2
+ if (!packageJSON.dependencies)
3
+ throw new Error('Package.json do not have dependencies')
4
+ if (packageJSON.dependencies['@inertiajs/vue3']) {
5
+ return 'vue'
6
+ } else if (packageJSON.dependencies['@inertiajs/react']) {
7
+ return 'react'
8
+ } else if (packageJSON.dependencies['@inertiajs/svelte']) {
9
+ return 'svelte'
10
+ } else {
11
+ throw new Error('Could not get UI framework from package.json.')
12
+ }
13
+ }