From 1c18e622e198bc50fabffec3a9d69fefdeaebcb8 Mon Sep 17 00:00:00 2001 From: Ryan Toronto Date: Wed, 17 Jul 2019 17:45:29 -0400 Subject: [PATCH] Breaking: Remove babel plugin to force sync relationships --- force-sync-relationships-plugin.js | 90 --------------- index.js | 12 -- node-tests/.eslintrc.js | 5 - .../belongs-to-as-identifier-test.js | 109 ------------------ .../belongs-to-as-member-expression-test.js | 109 ------------------ .../has-many-as-identiifer-test.js | 109 ------------------ .../has-many-as-member-expression-test.js | 109 ------------------ .../working-with-relationships/template.md | 42 +------ 8 files changed, 2 insertions(+), 583 deletions(-) delete mode 100644 force-sync-relationships-plugin.js delete mode 100644 node-tests/.eslintrc.js delete mode 100644 node-tests/force-sync-relationships-plugin/belongs-to-as-identifier-test.js delete mode 100644 node-tests/force-sync-relationships-plugin/belongs-to-as-member-expression-test.js delete mode 100644 node-tests/force-sync-relationships-plugin/has-many-as-identiifer-test.js delete mode 100644 node-tests/force-sync-relationships-plugin/has-many-as-member-expression-test.js diff --git a/force-sync-relationships-plugin.js b/force-sync-relationships-plugin.js deleted file mode 100644 index f2b52146..00000000 --- a/force-sync-relationships-plugin.js +++ /dev/null @@ -1,90 +0,0 @@ -/* eslint-env node */ -'use strict'; - -var isTesting = process.mainModule.filename.match('qunit'); - -function ForceSyncRelationshipsPlugin() { - return { - visitor: { - CallExpression(path) { - /* - path.node.callee.type -> Identifier - path.node.callee.name -> belongsTo - - and - - path.node.callee.type -> MemberExpression - path.node.callee.property.name -> belongsTo - */ - if (this.file.opts.filename.match('model') || isTesting) { - let isMemberExpression = path.node.callee.type === 'MemberExpression'; - let isIdentifier = path.node.callee.type === 'Identifier'; - let isHasManyMemberExpression = isMemberExpression && path.node.callee.property.name === 'hasMany'; - let isHasManyIdentifier = isIdentifier && path.node.callee.name === 'hasMany'; - let isHasMany = isHasManyMemberExpression || isHasManyIdentifier; - let isBelongsToMemberExpression = isMemberExpression && path.node.callee.property.name === 'belongsTo'; - let isBelongsToIdentifier = isIdentifier && path.node.callee.name === 'belongsTo'; - let isBelongsTo = isBelongsToMemberExpression || isBelongsToIdentifier; - - if ((isHasMany || isBelongsTo) && path.parent.type === 'ObjectProperty') { - let emptyObjectExpression = { - type: "ObjectExpression", - properties: [] - }; - let asyncFalseProperty = { - type: "ObjectProperty", - method: false, - shorthand: false, - key: { - type: "Identifier", - loc: { - identifierName: "async" - }, - name: "async" - }, - computed: false, - value: { - type: "BooleanLiteral", - value: false - } - }; - - let lastArgument = path.node.arguments.length > 0 && path.node.arguments[path.node.arguments.length - 1]; - let lastArgumentIsOptions = lastArgument.type === 'ObjectExpression'; - let indexOfOptions; - - if (lastArgumentIsOptions) { - indexOfOptions = path.node.arguments.length - 1; - let existingAsyncOption = lastArgument.properties.find(prop => prop.key.name === 'async'); - if (existingAsyncOption) { - /* - For now, let's throw for any value async. You can check the value with `existingAsyncOption.value.value`. - */ - throw path.buildCodeFrameError(`Ember Data Storefront: You've set forceSyncRelationships to "rewrite", so you should omit the async option on all relationships.`); - } else { - path.node.arguments[indexOfOptions].properties.push(asyncFalseProperty); - } - - } else { - path.node.arguments = path.node.arguments || []; - path.node.arguments.push(emptyObjectExpression); - indexOfOptions = path.node.arguments.length - 1; - - path.node.arguments[indexOfOptions].properties.push(asyncFalseProperty); - } - } - } - } - } - } -} - -ForceSyncRelationshipsPlugin.baseDir = function() { - return __dirname; -}; - -ForceSyncRelationshipsPlugin.cacheKey = function() { - return 'ember-data-storefront.force-sync-relationships'; -}; - -module.exports = ForceSyncRelationshipsPlugin; diff --git a/index.js b/index.js index c9d8449c..e0e3d0f6 100644 --- a/index.js +++ b/index.js @@ -25,18 +25,6 @@ module.exports = { this.app = app; this.addonConfig = this.app.project.config(app.env)['ember-data-storefront'] || {}; - - let validOptions = [ 'rewrite', undefined ]; - if (!validOptions.includes(this.addonConfig.forceSyncRelationships)) { - throw `[ Ember Data Storefront ] Invalid config option for forceSyncRelationships. You passed "${this.addonConfig.forceSyncRelationships}", must be one of ${validOptions.map(option => `"${option}"`).join(", ")}.`; - } - - if (this.addonConfig.forceSyncRelationships === 'rewrite') { - app.options = app.options || {}; - app.options.babel6 = app.options.babel6 || {}; - app.options.babel6.plugins = app.options.babel6.plugins || []; - app.options.babel6.plugins.push(require('./force-sync-relationships-plugin')); - } } }; diff --git a/node-tests/.eslintrc.js b/node-tests/.eslintrc.js deleted file mode 100644 index b764da4a..00000000 --- a/node-tests/.eslintrc.js +++ /dev/null @@ -1,5 +0,0 @@ -module.exports = { - env: { - qunit: true - } -}; diff --git a/node-tests/force-sync-relationships-plugin/belongs-to-as-identifier-test.js b/node-tests/force-sync-relationships-plugin/belongs-to-as-identifier-test.js deleted file mode 100644 index 9236e26e..00000000 --- a/node-tests/force-sync-relationships-plugin/belongs-to-as-identifier-test.js +++ /dev/null @@ -1,109 +0,0 @@ -/* eslint-env node */ -var babel = require('babel-core'); -var stripIndent = require('strip-indent'); -var ForceSynceRelationshipsPlugin = require('../../force-sync-relationships-plugin'); -var module = QUnit.module; -var test = QUnit.test; - -function testOriginalToTransformed(description, original, transformed) { - return test(description, function(assert) { - let strippedOriginal = stripIndent(original); - let strippedTransformed = stripIndent(transformed); - var result = babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - - assert.equal(result.code.trim(), strippedTransformed.trim()); - }); -} - -module('belongsTo as Identifier', function() { - - testOriginalToTransformed('it works when called with no arguments', - ` - export default Model.extend({ - - posts: belongsTo() - - }); - `, - ` - export default Model.extend({ - - posts: belongsTo({ - async: false - }) - - }); - `); - - testOriginalToTransformed('it works when called with a model name', - ` - export default Model.extend({ - - posts: belongsTo('post') - - }); - `, - ` - export default Model.extend({ - - posts: belongsTo('post', { - async: false - }) - - }); - ` - ); - - testOriginalToTransformed('it merges with options other than async', - ` - export default Model.extend({ - - posts: belongsTo({ inverse: 'foo' }) - - }); - `, - ` - export default Model.extend({ - - posts: belongsTo({ inverse: 'foo', async: false - }) - - }); - ` - ); - - test('it throws when it sees async: true', function(assert) { - let strippedOriginal = stripIndent(` - export default Model.extend({ - - posts: belongsTo({ async: true }) - - }); - `); - - assert.throws(() => { - babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - }); - }); - - test('it throws when it sees async: false', function(assert) { - let strippedOriginal = stripIndent(` - export default Model.extend({ - - posts: belongsTo({ async: false }) - - }); - `); - - assert.throws(() => { - babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - }); - }); - -}); diff --git a/node-tests/force-sync-relationships-plugin/belongs-to-as-member-expression-test.js b/node-tests/force-sync-relationships-plugin/belongs-to-as-member-expression-test.js deleted file mode 100644 index 4bf1b898..00000000 --- a/node-tests/force-sync-relationships-plugin/belongs-to-as-member-expression-test.js +++ /dev/null @@ -1,109 +0,0 @@ -/* eslint-env node */ -var babel = require('babel-core'); -var stripIndent = require('strip-indent'); -var ForceSynceRelationshipsPlugin = require('../../force-sync-relationships-plugin'); -var module = QUnit.module; -var test = QUnit.test; - -function testOriginalToTransformed(description, original, transformed) { - return test(description, function(assert) { - let strippedOriginal = stripIndent(original); - let strippedTransformed = stripIndent(transformed); - var result = babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - - assert.equal(result.code.trim(), strippedTransformed.trim()); - }); -} - -module('belongsTo as Member Expression', function() { - - testOriginalToTransformed('it works when called with no arguments', - ` - export default Model.extend({ - - posts: DS.belongsTo() - - }); - `, - ` - export default Model.extend({ - - posts: DS.belongsTo({ - async: false - }) - - }); - `); - - testOriginalToTransformed('it works when called with a model name', - ` - export default Model.extend({ - - posts: DS.belongsTo('post') - - }); - `, - ` - export default Model.extend({ - - posts: DS.belongsTo('post', { - async: false - }) - - }); - ` - ); - - testOriginalToTransformed('it merges with options other than async', - ` - export default Model.extend({ - - posts: DS.belongsTo({ inverse: 'foo' }) - - }); - `, - ` - export default Model.extend({ - - posts: DS.belongsTo({ inverse: 'foo', async: false - }) - - }); - ` - ); - - test('it throws when it sees async: true', function(assert) { - let strippedOriginal = stripIndent(` - export default Model.extend({ - - posts: DS.belongsTo({ async: true }) - - }); - `); - - assert.throws(() => { - babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - }); - }); - - test('it throws when it sees async: false', function(assert) { - let strippedOriginal = stripIndent(` - export default Model.extend({ - - posts: DS.belongsTo({ async: false }) - - }); - `); - - assert.throws(() => { - babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - }); - }); - -}); diff --git a/node-tests/force-sync-relationships-plugin/has-many-as-identiifer-test.js b/node-tests/force-sync-relationships-plugin/has-many-as-identiifer-test.js deleted file mode 100644 index 934b6904..00000000 --- a/node-tests/force-sync-relationships-plugin/has-many-as-identiifer-test.js +++ /dev/null @@ -1,109 +0,0 @@ -/* eslint-env node */ -var babel = require('babel-core'); -var stripIndent = require('strip-indent'); -var ForceSynceRelationshipsPlugin = require('../../force-sync-relationships-plugin'); -var module = QUnit.module; -var test = QUnit.test; - -function testOriginalToTransformed(description, original, transformed) { - return test(description, function(assert) { - let strippedOriginal = stripIndent(original); - let strippedTransformed = stripIndent(transformed); - var result = babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - - assert.equal(result.code.trim(), strippedTransformed.trim()); - }); -} - -module('hasMany as Identifier', function() { - - testOriginalToTransformed('it works when called with no arguments', - ` - export default Model.extend({ - - posts: hasMany() - - }); - `, - ` - export default Model.extend({ - - posts: hasMany({ - async: false - }) - - }); - `); - - testOriginalToTransformed('it works when called with a model name', - ` - export default Model.extend({ - - posts: hasMany('post') - - }); - `, - ` - export default Model.extend({ - - posts: hasMany('post', { - async: false - }) - - }); - ` - ); - - testOriginalToTransformed('it merges with options other than async', - ` - export default Model.extend({ - - posts: hasMany({ inverse: 'foo' }) - - }); - `, - ` - export default Model.extend({ - - posts: hasMany({ inverse: 'foo', async: false - }) - - }); - ` - ); - - test('it throws when it sees async: true', function(assert) { - let strippedOriginal = stripIndent(` - export default Model.extend({ - - posts: hasMany({ async: true }) - - }); - `); - - assert.throws(() => { - babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - }); - }); - - test('it throws when it sees async: false', function(assert) { - let strippedOriginal = stripIndent(` - export default Model.extend({ - - posts: hasMany({ async: false }) - - }); - `); - - assert.throws(() => { - babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - }); - }); - -}); diff --git a/node-tests/force-sync-relationships-plugin/has-many-as-member-expression-test.js b/node-tests/force-sync-relationships-plugin/has-many-as-member-expression-test.js deleted file mode 100644 index 2f08017a..00000000 --- a/node-tests/force-sync-relationships-plugin/has-many-as-member-expression-test.js +++ /dev/null @@ -1,109 +0,0 @@ -/* eslint-env node */ -var babel = require('babel-core'); -var stripIndent = require('strip-indent'); -var ForceSynceRelationshipsPlugin = require('../../force-sync-relationships-plugin'); -var module = QUnit.module; -var test = QUnit.test; - -function testOriginalToTransformed(description, original, transformed) { - return test(description, function(assert) { - let strippedOriginal = stripIndent(original); - let strippedTransformed = stripIndent(transformed); - var result = babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - - assert.equal(result.code.trim(), strippedTransformed.trim()); - }); -} - -module('DS.hasMany as Member Expression', function() { - - testOriginalToTransformed('it works when called with no arguments', - ` - export default Model.extend({ - - posts: DS.hasMany() - - }); - `, - ` - export default Model.extend({ - - posts: DS.hasMany({ - async: false - }) - - }); - `); - - testOriginalToTransformed('it works when called with a model name', - ` - export default Model.extend({ - - posts: DS.hasMany('post') - - }); - `, - ` - export default Model.extend({ - - posts: DS.hasMany('post', { - async: false - }) - - }); - ` - ); - - testOriginalToTransformed('it merges with options other than async', - ` - export default Model.extend({ - - posts: DS.hasMany({ inverse: 'foo' }) - - }); - `, - ` - export default Model.extend({ - - posts: DS.hasMany({ inverse: 'foo', async: false - }) - - }); - ` - ); - - test('it throws when it sees async: true', function(assert) { - let strippedOriginal = stripIndent(` - export default Model.extend({ - - posts: DS.hasMany({ async: true }) - - }); - `); - - assert.throws(() => { - babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - }); - }); - - test('it throws when it sees async: false', function(assert) { - let strippedOriginal = stripIndent(` - export default Model.extend({ - - posts: DS.hasMany({ async: false }) - - }); - `); - - assert.throws(() => { - babel.transform(strippedOriginal, { - plugins: [ ForceSynceRelationshipsPlugin ], - }); - }); - }); - -}); diff --git a/tests/dummy/app/pods/docs/guides/working-with-relationships/template.md b/tests/dummy/app/pods/docs/guides/working-with-relationships/template.md index 65a171af..38de69ac 100644 --- a/tests/dummy/app/pods/docs/guides/working-with-relationships/template.md +++ b/tests/dummy/app/pods/docs/guides/working-with-relationships/template.md @@ -52,44 +52,6 @@ Sync relationships maintain the expected behavior of `#get` – returning local **How to enforce sync-only relationships** -There a few ways you can avoid async relationships: +Follow the instructions and add the `force-sync-relationships` rule from our custom ESLint plugin to your app: [https://github.com/embermap/eslint-plugin-ember-data-sync-relationships](https://github.com/embermap/eslint-plugin-ember-data-sync-relationships) - - **Use our ESLint plugin.** Follow the instructions and add the `force-sync-relationships` rule from our custom ESLint plugin to your app: - - [https://github.com/embermap/eslint-plugin-ember-data-sync-relationships](https://github.com/embermap/eslint-plugin-ember-data-sync-relationships) - - You'll see the linting errors in your editor and console, and if you set the rule to `error`, your test suite will fail if any relationships are async. - - - **Use the included Babel plugin to rewrite all relationships to `async: false`.** This is a stronger but less apparent way to enforce sync relationships, so use it with caution. - - In `config/environment.js`, set the `ENV['ember-data-storefront'].forceSyncRelationships` option to `rewrite`: - - ```js - module.exports = function(environment) { - let ENV = { - 'ember-data-storefront': { - forceSyncRelationships: 'rewrite' - } - }; - } - ``` - - Now, all "bare" `hasMany` and `belongsTo` calls will be rewritten at build-time to include `{ async: false }` as an option. - - ```js - export default Model.extend({ - comments: hasMany(), // async: false - author: belongsTo(), // async: false - }); - ``` - - If you have a relationship with `async` specified at all (`true` or `false`), the plugin will fail your build. This is to keep relationship definitions as consistent as possible – with only one possible value, the option should be omitted entirely. - - ```js - export default Model.extend({ - posts: hasMany({ async: true }), // will fail the build - posts: hasMany({ async: false }), // will also fail the build - }); - ``` - - In a sense, the `rewrite` option effectively changes the default behavior of `belongsTo` and `hasMany`. +You'll see the linting errors in your editor and console, and if you set the rule to `error`, your test suite will fail if any relationships are async.