@kaspernj/api-maker 1.0.147 → 1.0.148

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/.eslintrc.js CHANGED
@@ -317,6 +317,7 @@ module.exports = {
317
317
  "jest/consistent-test-it": "off",
318
318
  "jest/prefer-called-with": "off",
319
319
  "jest/prefer-expect-assertions": "off",
320
+ "jest/prefer-hooks-in-order": "error",
320
321
  "jest/prefer-strict-equal": "off",
321
322
  "no-shadow": "off",
322
323
  "jest/prefer-to-have-length": "off",
package/index.js CHANGED
@@ -1,87 +1 @@
1
- const Api = require("./src/api.cjs")
2
- const AttributeNotLoadedError = require("./src/attribute-not-loaded-error.cjs")
3
- const BaseModel = require("./src/base-model.cjs")
4
- const CableConnectionPool = require("./src/cable-connection-pool.cjs")
5
- const CanCan = require("./src/can-can.cjs")
6
- const CanCanLoader = require("./src/can-can-loader.jsx").default
7
- const Collection = require("./src/collection.cjs")
8
- const CommandSubmitData = require("./src/command-submit-data.cjs")
9
- const CommandsPool = require("./src/commands-pool.cjs")
10
- const CustomError = require("./src/custom-error.cjs")
11
- const Deserializer = require("./src/deserializer.cjs")
12
- const Devise = require("./src/devise.cjs")
13
- const ErrorLogger = require("./src/error-logger.cjs")
14
- const EventConnection = require("./src/event-connection").default
15
- const EventCreated = require("./src/event-created").default
16
- const EventDestroyed = require("./src/event-destroyed").default
17
- const EventEmitterListener = require("./src/event-emitter-listener").default
18
- const EventListener = require("./src/event-listener").default
19
- const EventModelClass = require("./src/event-model-class").default
20
- const EventUpdated = require("./src/event-updated").default
21
- const instanceOfClassName = require("./src/instance-of-class-name.cjs")
22
- const KeyValueStore = require("./src/key-value-store.cjs")
23
- const Logger = require("./src/logger.cjs")
24
- const ModelName = require("./src/model-name.cjs")
25
- const ModelPropType = require("./src/model-prop-type.cjs")
26
- const ModelsResponseReader = require("./src/models-response-reader.cjs")
27
- const MoneyFormatter = require("./src/money-formatter.cjs")
28
- const NotLoadedError = require("./src/not-loaded-error.cjs")
29
- const Params = require("./src/params.cjs")
30
- const Preloaded = require("./src/preloaded.cjs")
31
- const RoutesNative = require("./src/routes-native.cjs")
32
- const ResourceRoute = require("./src/resource-route.cjs")
33
- const ResourceRoutes = require("./src/resource-routes").default
34
- const Result = require("./src/result.cjs")
35
- const Routes = require("./src/routes.cjs")
36
- const Serializer = require("./src/serializer.cjs")
37
- const Services = require("./src/services.cjs")
38
- const SessionStatusUpdater = require("./src/session-status-updater.cjs")
39
- const SourceMapsLoader = require("./src/source-maps-loader.cjs")
40
- const UpdatedAttribute = require("./src/updated-attribute").default
41
- const ValidationError = require("./src/validation-error.cjs")
42
- const {ValidationErrors} = require("./src/validation-errors.cjs")
43
-
44
- export {
45
- Api,
46
- AttributeNotLoadedError,
47
- BaseModel,
48
- CableConnectionPool,
49
- CanCan,
50
- CanCanLoader,
51
- Collection,
52
- CommandSubmitData,
53
- CommandsPool,
54
- CustomError,
55
- Deserializer,
56
- Devise,
57
- ErrorLogger,
58
- EventConnection,
59
- EventCreated,
60
- EventDestroyed,
61
- EventEmitterListener,
62
- EventListener,
63
- EventModelClass,
64
- EventUpdated,
65
- instanceOfClassName,
66
- KeyValueStore,
67
- Logger,
68
- ModelName,
69
- ModelPropType,
70
- ModelsResponseReader,
71
- MoneyFormatter,
72
- NotLoadedError,
73
- Params,
74
- Preloaded,
75
- ResourceRoute,
76
- ResourceRoutes,
77
- Result,
78
- Routes,
79
- RoutesNative,
80
- Serializer,
81
- Services,
82
- SessionStatusUpdater,
83
- SourceMapsLoader,
84
- UpdatedAttribute,
85
- ValidationError,
86
- ValidationErrors
87
- }
1
+ export {}
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  ]
17
17
  },
18
18
  "name": "@kaspernj/api-maker",
19
- "version": "1.0.147",
19
+ "version": "1.0.148",
20
20
  "description": "",
21
21
  "main": "index.js",
22
22
  "repository": {
@@ -56,7 +56,6 @@
56
56
  "prop-types": "^15.7.2",
57
57
  "prop-types-exact": ">= 1.2.0",
58
58
  "react": ">= 17.0.2",
59
- "react-router-dom": ">= 5.2.0",
60
59
  "react-test-renderer": "^17.0.1",
61
60
  "source-map": "^0.7.3",
62
61
  "stacktrace-parser": ">= 0.1.9"
@@ -329,7 +329,9 @@ class BaseModel {
329
329
  static humanAttributeName (attributeName) {
330
330
  const keyName = digg(this.modelClassData(), "i18nKey")
331
331
 
332
- return shared.i18n.t(`activerecord.attributes.${keyName}.${BaseModel.snakeCase(attributeName)}`, {defaultValue: attributeName})
332
+ if (shared.i18n) return shared.i18n.t(`activerecord.attributes.${keyName}.${BaseModel.snakeCase(attributeName)}`, {defaultValue: attributeName})
333
+
334
+ return inflection.humanize(attributeName)
333
335
  }
334
336
 
335
337
  isAttributeChanged (attributeName) {
@@ -783,7 +785,10 @@ class BaseModel {
783
785
  const relationshipClassData = relationships.find((relationship) => digg(relationship, "name") == relationshipName)
784
786
 
785
787
  if (!relationshipClassData) {
786
- throw new Error(`Could not find the relation ${relationshipName} on the ${digg(this.modelClassData(), "name")} model`)
788
+ const modelName = digg(this.modelClassData(), "name")
789
+ const relationshipsList = relationships.map((relationship) => relationship.name).join(", ")
790
+
791
+ throw new Error(`Could not find the relation ${relationshipName} on the ${modelName} model: ${relationshipsList}`)
787
792
  }
788
793
 
789
794
  const relationshipType = digg(relationshipClassData, "collectionName")
package/src/can-can.cjs CHANGED
@@ -33,7 +33,7 @@ module.exports = class ApiMakerCanCan {
33
33
  subjectLabel = digg(subject.modelClassData(), "name")
34
34
  }
35
35
 
36
- console.error(`Ability not loaded ${subjectLabel}#${abilityToUse}`)
36
+ console.error(`Ability not loaded ${subjectLabel}#${abilityToUse}`, {abilities: this.abilities, ability, subject})
37
37
 
38
38
  return false
39
39
  } else {
@@ -42,7 +42,26 @@ module.exports = class ApiMakerCanCan {
42
42
  }
43
43
 
44
44
  findAbility (ability, subject) {
45
- return this.abilities.find((abilityData) => digg(abilityData, "subject") == subject && digg(abilityData, "ability") == ability)
45
+ return this.abilities.find((abilityData) => {
46
+ const abilityDataSubject = digg(abilityData, "subject")
47
+ const abilityDataAbility = digg(abilityData, "ability")
48
+
49
+ // If actually same class
50
+ if (abilityDataSubject == subject && abilityDataAbility == ability) return true
51
+
52
+ // Sometimes in dev when using linking it will actually be two different but identical resource classes
53
+ if (
54
+ typeof subject == "function" &&
55
+ subject.modelClassData &&
56
+ typeof abilityDataSubject == "function" &&
57
+ abilityDataSubject.modelClassData &&
58
+ digg(subject.modelClassData(), "name") == digg(abilityDataSubject.modelClassData(), "name")
59
+ ) {
60
+ return true
61
+ }
62
+
63
+ return false
64
+ })
46
65
  }
47
66
 
48
67
  isAbilityLoaded (ability, subject) {
@@ -5,11 +5,12 @@ const EventCreated = require("@kaspernj/api-maker/src/event-created").default
5
5
  const EventDestroyed = require("@kaspernj/api-maker/src/event-destroyed").default
6
6
  const EventUpdated = require("@kaspernj/api-maker/src/event-updated").default
7
7
  const instanceOfClassName = require("@kaspernj/api-maker/src/instance-of-class-name")
8
- const {LocationChanged} = require("on-location-changed/location-changed-component")
9
8
  const Params = require("@kaspernj/api-maker/src/params")
10
9
  const PropTypes = require("prop-types")
11
10
  const React = require("react")
12
11
 
12
+ import {LocationChanged} from "on-location-changed/src/location-changed-component"
13
+
13
14
  export default class CollectionLoader extends React.PureComponent {
14
15
  static defaultProps = {
15
16
  destroyEnabled: true,
package/src/config.js CHANGED
@@ -14,6 +14,10 @@ class ApiMakerConfig {
14
14
  setCurrenciesCollection(newCurrenciesCollection) {
15
15
  this.global.currenciesCollection = newCurrenciesCollection
16
16
  }
17
+
18
+ setHistory(history) {
19
+ this.global.history = history
20
+ }
17
21
  }
18
22
 
19
23
  const apiMakerConfig = new ApiMakerConfig()
@@ -8,9 +8,17 @@ module.exports = class ApiMakerDeserializer {
8
8
  if (Array.isArray(object)) {
9
9
  return object.map((value) => ApiMakerDeserializer.parse(value))
10
10
  } else if (object && typeof object == "object") {
11
- if (object.api_maker_type == "date" || object.api_maker_type == "time") {
11
+ if (object.api_maker_type == "date") {
12
12
  const date = new Date(digg(object, "value"))
13
13
 
14
+ date.apiMakerType = "date"
15
+
16
+ return date
17
+ } else if (object.api_maker_type == "time") {
18
+ const date = new Date(digg(object, "value"))
19
+
20
+ date.apiMakerType = "time"
21
+
14
22
  return date
15
23
  } else if (object.api_maker_type == "collection") {
16
24
  // Need to remove type to avoid circular error
package/src/link.jsx ADDED
@@ -0,0 +1,21 @@
1
+ import React from "react"
2
+
3
+ export default class Link extends React.PureComponent {
4
+ render() {
5
+ const {to, ...restProps} = this.props
6
+
7
+ return (
8
+ <a href={to} {...restProps} onClick={this.onLinkClicked} />
9
+ )
10
+ }
11
+
12
+ onLinkClicked = (e) => {
13
+ e.preventDefault()
14
+
15
+ const history = global.apiMakerConfigGlobal?.history
16
+
17
+ if (!history) throw new Error("History hasn't been set in the API maker configuration")
18
+
19
+ history.push(this.props.to)
20
+ }
21
+ }
package/src/router.jsx ADDED
@@ -0,0 +1,129 @@
1
+ import escapeStringRegexp from "escape-string-regexp"
2
+ import inflection from "inflection"
3
+ import PropTypes from "prop-types"
4
+ import React from "react"
5
+ import {shouldComponentUpdate} from "set-state-compare"
6
+ import {Suspense} from "react"
7
+
8
+ export default class ApiMakerRouter extends React.Component {
9
+ static propTypes = {
10
+ notFoundComponent: PropTypes.elementType,
11
+ path: PropTypes.string.isRequired,
12
+ requireComponent: PropTypes.func.isRequired,
13
+ routes: PropTypes.object,
14
+ routeDefinitions: PropTypes.object
15
+ }
16
+
17
+ parsedRouteDefinitions = this.parseRouteDefinitions()
18
+
19
+ shouldComponentUpdate(nextProps, nextState) {
20
+ return shouldComponentUpdate(this, nextProps, nextState)
21
+ }
22
+
23
+ findRouteParams (routeDefinition) {
24
+ const result = []
25
+ const parts = routeDefinition.path.split("/")
26
+
27
+ for (const part of parts) {
28
+ if (part.match(/^:([a-z_]+)$/))
29
+ result.push(part)
30
+ }
31
+
32
+ return result
33
+ }
34
+
35
+ parseRouteDefinitions() {
36
+ const Locales = require("shared/locales").default
37
+ const {routeDefinitions, routes} = this.props
38
+ const regex = /:([A-z\d_]+)/
39
+ const parsedRouteDefinitions = []
40
+
41
+ for (const locale of Locales.availableLocales()) {
42
+ for (const routeDefinition of routeDefinitions.routes) {
43
+ const routePathName = `${inflection.camelize(routeDefinition.name, true)}Path`
44
+ const params = this.findRouteParams(routeDefinition)
45
+
46
+ params.push({locale})
47
+
48
+ if (!(routePathName in routes))
49
+ throw new Error(`${routePathName} not found in routes: ${Object.keys(routes, ", ")}`)
50
+
51
+ const routePath = routes[routePathName](...params)
52
+ const groups = []
53
+
54
+ let pathRegexString = '^'
55
+
56
+ pathRegexString += escapeStringRegexp(routePath)
57
+
58
+ while (true) {
59
+ const match = pathRegexString.match(regex)
60
+
61
+ if (!match) break
62
+
63
+ const variableName = match[1]
64
+
65
+ groups.push(variableName)
66
+
67
+ pathRegexString = pathRegexString.replace(match[0], `([^\/]+)`)
68
+ }
69
+
70
+ pathRegexString += '$'
71
+
72
+ const pathRegex = new RegExp(pathRegexString)
73
+
74
+ parsedRouteDefinitions.push({groups, pathRegex, routeDefinition})
75
+ }
76
+ }
77
+
78
+ return parsedRouteDefinitions
79
+ }
80
+
81
+ findMatchingRoute() {
82
+ const path = this.props.path.replace(/[\/]+$/, "")
83
+
84
+ for (const parsedRouteDefinition of this.parsedRouteDefinitions) {
85
+ const match = path.match(parsedRouteDefinition.pathRegex)
86
+ let matched, params
87
+
88
+ if (match) {
89
+ matched = true
90
+ params = {}
91
+
92
+ for (const groupKey in parsedRouteDefinition.groups) {
93
+ const groupName = parsedRouteDefinition.groups[groupKey]
94
+
95
+ params[groupName] = match[Number(groupKey) + 1]
96
+ }
97
+ }
98
+
99
+ if (path == "" && parsedRouteDefinition.routeDefinition.path == "/") matched = true
100
+ if (matched) return {params, parsedRouteDefinition}
101
+ }
102
+ }
103
+
104
+ render() {
105
+ const matchingRoute = this.findMatchingRoute()
106
+
107
+ if (!matchingRoute) {
108
+ if (this.props.notFoundComponent) {
109
+ const NotFoundComponent = this.props.notFoundComponent
110
+
111
+ return (
112
+ <Suspense fallback={<div />}>
113
+ <NotFoundComponent />
114
+ </Suspense>
115
+ )
116
+ } else {
117
+ return null
118
+ }
119
+ }
120
+
121
+ const Component = this.props.requireComponent({routeDefinition: matchingRoute.parsedRouteDefinition.routeDefinition})
122
+
123
+ return (
124
+ <Suspense fallback={<div />}>
125
+ <Component match={{params: matchingRoute.params}} />
126
+ </Suspense>
127
+ )
128
+ }
129
+ }
@@ -1,82 +0,0 @@
1
- const {digg} = require("diggerize")
2
- const inflection = require("inflection")
3
-
4
- module.exports = class ApiMakerResourceRoute {
5
- constructor ({jsRoutes, locales, requireComponent, routeDefinition}) {
6
- this.jsRoutes = jsRoutes
7
- this.locales = locales
8
- this.requireComponent = requireComponent
9
- this.routeDefinition = routeDefinition
10
-
11
- if (!jsRoutes) {
12
- throw new Error("No 'jsRoutes' given")
13
- }
14
- }
15
-
16
- routesResult () {
17
- if (digg(this, "locales")) {
18
- return this.withLocale()
19
- } else {
20
- return this.withoutLocale()
21
- }
22
- }
23
-
24
- findRouteParams () {
25
- const result = []
26
- const parts = digg(this, "routeDefinition", "path").split("/")
27
-
28
- for (const part of parts) {
29
- if (part.match(/^:([a-z_]+)$/))
30
- result.push(part)
31
- }
32
-
33
- return result
34
- }
35
-
36
- requireComponentFromCaller () {
37
- return this.requireComponent({
38
- routeDefinition: digg(this, "routeDefinition")
39
- })
40
- }
41
-
42
- withLocale () {
43
- const component = this.requireComponentFromCaller()
44
- const Locales = require("shared/locales").default
45
- const routes = []
46
-
47
- for (const locale of Locales.availableLocales()) {
48
- const routePathName = `${inflection.camelize(digg(this, "routeDefinition", "name"), true)}Path`
49
- const params = this.findRouteParams()
50
-
51
- params.push({locale})
52
-
53
- if (!(routePathName in this.jsRoutes)) {
54
- throw new Error(`${routePathName} not found in routes: ${Object.keys(this.jsRoutes, ", ")}`)
55
- }
56
-
57
- const path = this.jsRoutes[routePathName](...params)
58
-
59
- routes.push({path, component})
60
- }
61
-
62
- return routes
63
- }
64
-
65
- withoutLocale () {
66
- const routePathName = inflection.camelize(digg(this, "routeDefinition", "name"), true)
67
- const routePathMethod = this.jsRoutes[`${routePathName}Path`]
68
-
69
- if (!routePathMethod)
70
- throw new Error(`No such route could be found: ${routePathName}`)
71
-
72
- const path = routePathMethod.apply(null, this.findRouteParams())
73
- const component = this.requireComponentFromCaller()
74
-
75
- return [
76
- {
77
- path,
78
- component
79
- }
80
- ]
81
- }
82
- }
@@ -1,30 +0,0 @@
1
- const {digg} = require("diggerize")
2
- const React = require("react")
3
- const ResourceRoute = require("./resource-route.cjs")
4
- const {Route} = require("react-router-dom")
5
-
6
- export default class ApiMakerResourceRoutes {
7
- static readRoutes ({jsRoutes, locales, requireComponent, routeDefinitions}) {
8
- if (!routeDefinitions)
9
- throw new Error("Please pass 'routeDefinitions' to this method")
10
-
11
- const routes = []
12
-
13
- for (const routeDefinition of routeDefinitions.routes) {
14
- const resourceRoute = new ResourceRoute({jsRoutes, locales, requireComponent, routeDefinition})
15
-
16
- for (const newRoute of resourceRoute.routesResult()) {
17
- routes.push(
18
- <Route
19
- component={digg(newRoute, "component")}
20
- exact
21
- key={`route-${digg(newRoute, "path")}`}
22
- path={digg(newRoute, "path")}
23
- />
24
- )
25
- }
26
- }
27
-
28
- return routes
29
- }
30
- }