@atlaskit/eslint-plugin-platform 2.4.2 → 2.6.0

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/afm-cc/tsconfig.json +1 -1
  3. package/dist/cjs/index.js +42 -3
  4. package/dist/cjs/rules/ensure-native-and-af-exports-synced/index.js +3 -0
  5. package/dist/cjs/rules/ensure-no-private-dependencies/index.js +101 -0
  6. package/dist/cjs/rules/ensure-valid-platform-yarn-protocol-usage/index.js +3 -15
  7. package/dist/cjs/rules/feature-gating/no-preconditioning/index.js +1 -1
  8. package/dist/cjs/rules/no-direct-document-usage/index.js +103 -0
  9. package/dist/cjs/rules/no-sparse-checkout/index.js +43 -0
  10. package/dist/cjs/rules/util/file-exclusions.js +45 -0
  11. package/dist/es2019/index.js +42 -3
  12. package/dist/es2019/rules/ensure-native-and-af-exports-synced/index.js +3 -0
  13. package/dist/es2019/rules/ensure-no-private-dependencies/index.js +63 -0
  14. package/dist/es2019/rules/ensure-valid-platform-yarn-protocol-usage/index.js +4 -16
  15. package/dist/es2019/rules/feature-gating/no-preconditioning/index.js +1 -1
  16. package/dist/es2019/rules/no-direct-document-usage/index.js +95 -0
  17. package/dist/es2019/rules/no-sparse-checkout/index.js +35 -0
  18. package/dist/es2019/rules/util/file-exclusions.js +37 -0
  19. package/dist/esm/index.js +42 -3
  20. package/dist/esm/rules/ensure-native-and-af-exports-synced/index.js +3 -0
  21. package/dist/esm/rules/ensure-no-private-dependencies/index.js +96 -0
  22. package/dist/esm/rules/ensure-valid-platform-yarn-protocol-usage/index.js +4 -16
  23. package/dist/esm/rules/feature-gating/no-preconditioning/index.js +1 -1
  24. package/dist/esm/rules/no-direct-document-usage/index.js +97 -0
  25. package/dist/esm/rules/no-sparse-checkout/index.js +37 -0
  26. package/dist/esm/rules/util/file-exclusions.js +39 -0
  27. package/dist/types/index.d.ts +14 -0
  28. package/dist/types/rules/ensure-no-private-dependencies/index.d.ts +3 -0
  29. package/dist/types/rules/no-direct-document-usage/index.d.ts +3 -0
  30. package/dist/types/rules/no-sparse-checkout/index.d.ts +3 -0
  31. package/dist/types/rules/util/file-exclusions.d.ts +13 -0
  32. package/dist/types-ts4.5/index.d.ts +14 -0
  33. package/dist/types-ts4.5/rules/ensure-no-private-dependencies/index.d.ts +3 -0
  34. package/dist/types-ts4.5/rules/no-direct-document-usage/index.d.ts +3 -0
  35. package/dist/types-ts4.5/rules/no-sparse-checkout/index.d.ts +3 -0
  36. package/dist/types-ts4.5/rules/util/file-exclusions.d.ts +13 -0
  37. package/package.json +12 -2
  38. package/src/index.tsx +46 -2
  39. package/src/rules/ensure-native-and-af-exports-synced/index.tsx +3 -0
  40. package/src/rules/ensure-no-private-dependencies/__tests__/unit/rule.test.ts +212 -0
  41. package/src/rules/ensure-no-private-dependencies/index.ts +64 -0
  42. package/src/rules/ensure-valid-bin-values/__tests__/unit/rule.test.ts +3 -2
  43. package/src/rules/ensure-valid-platform-yarn-protocol-usage/__tests__/unit/rule.test.ts +57 -109
  44. package/src/rules/ensure-valid-platform-yarn-protocol-usage/index.ts +4 -16
  45. package/src/rules/feature-gating/no-preconditioning/index.tsx +1 -1
  46. package/src/rules/no-direct-document-usage/index.tsx +109 -0
  47. package/src/rules/no-sparse-checkout/__tests__/unit/rule.test.tsx +48 -0
  48. package/src/rules/no-sparse-checkout/index.tsx +54 -0
  49. package/src/rules/util/file-exclusions.ts +39 -0
@@ -0,0 +1,63 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+
3
+ import { getObjectPropertyAsObject, getObjectPropertyAsLiteral } from '../util/handle-ast-object';
4
+ import { getPackagesSync } from '@manypkg/get-packages';
5
+ import { findRootSync } from '@manypkg/find-root';
6
+ const root = findRootSync(process.cwd());
7
+ const pkgs = getPackagesSync(root).packages;
8
+ const pkgMap = new Map(pkgs.map(pkg => [pkg.packageJson.name, pkg]));
9
+ const rule = {
10
+ meta: {
11
+ type: 'problem',
12
+ docs: {
13
+ description: `Ensures that private dependencies are not used in published packages.`,
14
+ recommended: true
15
+ },
16
+ hasSuggestions: false,
17
+ messages: {
18
+ invalidPrivateDependency: `Published package has private dependency '{{ pkgName }}'. To resolve this error, remove the private dependency or set this package to private.`
19
+ }
20
+ },
21
+ create(context) {
22
+ return {
23
+ ObjectExpression: async node => {
24
+ // Only run this rule on package.json files
25
+ if (!context.filename.endsWith('package.json') || node.type !== 'ObjectExpression') {
26
+ return;
27
+ }
28
+
29
+ // Private dependencies can be used in private packages
30
+ const isPrivatePkg = getObjectPropertyAsLiteral(node, 'private') === true;
31
+ if (isPrivatePkg === true) {
32
+ return;
33
+ }
34
+
35
+ // Check for private dependencies in dependencies and peerDependencies
36
+ // Note: devDependencies are not checked here as they don't end up in consumer lockfiles
37
+ const dependencies = getObjectPropertyAsObject(node, 'dependencies');
38
+ const peerDependencies = getObjectPropertyAsObject(node, 'peerDependencies');
39
+ for (const obj of [dependencies, peerDependencies]) {
40
+ for (const p of (obj === null || obj === void 0 ? void 0 : obj.properties) || []) {
41
+ if (p.type === 'Property' && p.key.type === 'Literal') {
42
+ const key = p.key.value;
43
+ if (typeof key === 'string' && pkgMap.has(key)) {
44
+ var _pkgMap$get;
45
+ const isPrivateDependency = ((_pkgMap$get = pkgMap.get(key)) === null || _pkgMap$get === void 0 ? void 0 : _pkgMap$get.packageJson.private) === true;
46
+ if (isPrivateDependency) {
47
+ context.report({
48
+ node,
49
+ messageId: 'invalidPrivateDependency',
50
+ data: {
51
+ pkgName: key
52
+ }
53
+ });
54
+ }
55
+ }
56
+ }
57
+ }
58
+ }
59
+ }
60
+ };
61
+ }
62
+ };
63
+ export default rule;
@@ -1,7 +1,6 @@
1
1
  // eslint-disable-next-line import/no-extraneous-dependencies
2
2
 
3
- import { getObjectPropertyAsObject, getObjectPropertyAsLiteral } from '../util/handle-ast-object';
4
- const workspaceProtocolRegex = /^workspace:[\^~\*]$/;
3
+ import { getObjectPropertyAsObject } from '../util/handle-ast-object';
5
4
  const rootProtocolRegex = /^root:[\^~\*]$/;
6
5
 
7
6
  /**
@@ -14,13 +13,11 @@ function getYarnProtocolsUsed(node) {
14
13
  };
15
14
  const dependencies = getObjectPropertyAsObject(node, 'dependencies');
16
15
  const devDependencies = getObjectPropertyAsObject(node, 'devDependencies');
17
- for (const obj of [dependencies, devDependencies]) {
16
+ const peerDependencies = getObjectPropertyAsObject(node, 'peerDependencies');
17
+ for (const obj of [dependencies, devDependencies, peerDependencies]) {
18
18
  for (const p of (obj === null || obj === void 0 ? void 0 : obj.properties) || []) {
19
19
  if (p.type === 'Property' && p.value.type === 'Literal') {
20
20
  if (typeof p.value.value === 'string') {
21
- if (workspaceProtocolRegex.test(p.value.value)) {
22
- protocolsUsed.workspace = true;
23
- }
24
21
  if (rootProtocolRegex.test(p.value.value)) {
25
22
  protocolsUsed.root = true;
26
23
  }
@@ -39,7 +36,7 @@ const rule = {
39
36
  },
40
37
  hasSuggestions: false,
41
38
  messages: {
42
- invalidWorkspaceProtocolUsage: `The 'workspace:' protocol is not allowed in public packages. To resolve this error, either set the package to private or replace the 'workspace:' protocol with specific package versions (e.g. '^1.0.0').`,
39
+ invalidWorkspaceProtocolUsage: `The 'workspace:^'protocol is Used. To resolve this error, please use the 'workspace:*' protocol instead.`,
43
40
  invalidRootProtocolUsage: `The 'root:' protocol is not allowed in platform packages. To resolve this error, replace the 'root:' protocol with specific package versions (e.g. '^1.0.0').`
44
41
  }
45
42
  },
@@ -58,15 +55,6 @@ const rule = {
58
55
  messageId: 'invalidRootProtocolUsage'
59
56
  });
60
57
  }
61
-
62
- // The 'workspace:' protocol can not be used in public packages
63
- const isPrivatePackage = getObjectPropertyAsLiteral(node, 'private') === true;
64
- if (!isPrivatePackage && yarnProtocolsUsed.workspace) {
65
- context.report({
66
- node,
67
- messageId: 'invalidWorkspaceProtocolUsage'
68
- });
69
- }
70
58
  }
71
59
  };
72
60
  }
@@ -50,7 +50,7 @@ const rule = {
50
50
  url: 'https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/browse/platform/packages/platform/eslint-plugin/src/rules/no-preconditioning/README.md'
51
51
  },
52
52
  messages: {
53
- useConfig: 'Do not precondition gates or experiments with another gate. Configure this in Statsig instead to reduce unnecessary code and simplify cleanup.',
53
+ useConfig: 'Do not precondition gates or experiments with another gate. Configure this in Statsig instead to reduce unnecessary code, simplify cleanup and to ensure accurate exposures in Statsig.',
54
54
  incorrectExposure: 'Evaluate gates or experiments at the end of your logical expression to ensure exposure is tracked correctly.'
55
55
  }
56
56
  },
@@ -0,0 +1,95 @@
1
+ import { skipForExampleFiles, skipForTestFiles } from '../util/file-exclusions';
2
+ const rule = {
3
+ meta: {
4
+ type: 'problem',
5
+ docs: {
6
+ description: 'Enforce using getDocument from @atlaskit/browser-apis instead of direct document usage',
7
+ recommended: true
8
+ },
9
+ messages: {
10
+ useGetDocument: 'Use getDocument from @atlaskit/browser-apis instead of direct document usage'
11
+ },
12
+ schema: []
13
+ },
14
+ create(context) {
15
+ let hasGetDocumentImport = false;
16
+ const filename = context.filename;
17
+
18
+ // Skip test files
19
+ const skipResult = skipForTestFiles(context);
20
+ if (skipResult) {
21
+ return skipResult;
22
+ }
23
+
24
+ // Skip example files
25
+ const skipResult2 = skipForExampleFiles(context);
26
+ if (skipResult2) {
27
+ return skipResult2;
28
+ }
29
+
30
+ // Skip the getDocument.ts file itself
31
+ if (filename.endsWith('getDocument.ts')) {
32
+ return {};
33
+ }
34
+ return {
35
+ ImportDeclaration(node) {
36
+ if (node.source.value === '@atlaskit/browser-apis' && node.specifiers.some(specifier => specifier.type === 'ImportSpecifier' && specifier.imported.name === 'getDocument')) {
37
+ hasGetDocumentImport = true;
38
+ }
39
+ },
40
+ Identifier(node) {
41
+ if (node.name === 'document' && !hasGetDocumentImport) {
42
+ const parent = node.parent;
43
+
44
+ // Skip if 'document' is used as a property key in an object literal
45
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.key === node) {
46
+ return;
47
+ }
48
+
49
+ // Skip if 'document' is used as a shorthand property value
50
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.value === node && parent.shorthand) {
51
+ return;
52
+ }
53
+
54
+ // Skip if 'document' is used as a property being accessed in a member expression
55
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MemberExpression' && parent.property === node && !parent.computed) {
56
+ return;
57
+ }
58
+
59
+ // Skip if 'document' is being declared as a variable
60
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'VariableDeclarator' && parent.id === node) {
61
+ return;
62
+ }
63
+
64
+ // Skip if 'document' is a function name
65
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'FunctionDeclaration' && 'id' in parent && parent.id === node) {
66
+ return;
67
+ }
68
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'FunctionExpression' && 'id' in parent && parent.id === node) {
69
+ return;
70
+ }
71
+
72
+ // Skip if 'document' is a method name in a class or object
73
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MethodDefinition' && parent.key === node) {
74
+ return;
75
+ }
76
+
77
+ // Skip if 'document' is being assigned to (shadowing the global)
78
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'AssignmentExpression' && parent.left === node) {
79
+ return;
80
+ }
81
+
82
+ // Skip if 'document' is in a destructuring pattern (could be destructuring from an object)
83
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'ObjectPattern' || (parent === null || parent === void 0 ? void 0 : parent.type) === 'ArrayPattern') {
84
+ return;
85
+ }
86
+ context.report({
87
+ node,
88
+ messageId: 'useGetDocument'
89
+ });
90
+ }
91
+ }
92
+ };
93
+ }
94
+ };
95
+ export default rule;
@@ -0,0 +1,35 @@
1
+ // We will be removing sparse checkout from pipelines in CI completely due to the load it causes on BBC.
2
+ // We will be incrementally removing sparse-checkout from the files below as it is probably unnecessasry.
3
+ // If you must add an exception below, please go through the chopper process before doing so
4
+ const sparseCheckoutExceptions = ['bitbucket-pipelines/pipelines/custom/run-issue-automat.ts', 'bitbucket-pipelines/pipelines/custom/marketplace/utils.ts', 'bitbucket-pipelines/pipelines/custom/confluence/utils/index.ts', 'bitbucket-pipelines/pipelines/custom/afm-tools/upload-afm-dependency-graph-cache.ts', 'bitbucket-pipelines/pipelines/custom/afm-tools/default-afm-tools.ts', 'bitbucket-pipelines/pipelines/custom/marketplace/utils.ts', 'bitbucket-pipelines/pipelines/custom/afm-git-hooks.ts', 'bitbucket-pipelines/pipelines/custom/update-codeowners-and-teams-gen.ts', 'bitbucket-pipelines/pipelines/custom/run-issue-automat.ts'];
5
+ const rule = {
6
+ meta: {
7
+ docs: {
8
+ recommended: false
9
+ },
10
+ type: 'problem',
11
+ messages: {
12
+ noSparseCheckout: 'Sparse checkout is not allowed in pipeline configurations. Use git-alternates instead by setting sparseCheckout to false or add this file to exceptions.'
13
+ }
14
+ },
15
+ create(context) {
16
+ const fileName = context.filename;
17
+ if (sparseCheckoutExceptions.some(exception => fileName.endsWith(exception))) {
18
+ return {};
19
+ }
20
+ return {
21
+ // Look for calls to afmClone or objects that match AFMCloneConfig type
22
+ 'CallExpression[callee.object.name=alias][callee.property.name=afmClone] ObjectExpression Property': node => {
23
+ if (node.key.type === 'Identifier' && node.key.name === 'sparseCheckout') {
24
+ if (node.value.type === 'Literal' && node.value.value === true) {
25
+ context.report({
26
+ node,
27
+ messageId: 'noSparseCheckout'
28
+ });
29
+ }
30
+ }
31
+ }
32
+ };
33
+ }
34
+ };
35
+ export default rule;
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Common patterns for test files that should be excluded from rules
3
+ */
4
+ const TEST_FILE_PATTERNS = ['__tests__', 'test', 'spec'];
5
+
6
+ /**
7
+ * Checks if a file should be excluded from rules based on test file patterns
8
+ * @param filename The filename to check
9
+ * @returns true if the file should be excluded, false otherwise
10
+ */
11
+ const isTestFile = filename => {
12
+ return TEST_FILE_PATTERNS.some(pattern => filename.includes(pattern));
13
+ };
14
+
15
+ /**
16
+ * Helper function to skip rules for test files
17
+ * @param context The ESLint rule context
18
+ * @returns An empty RuleListener if the file is a test file, undefined otherwise
19
+ */
20
+ export const skipForTestFiles = context => {
21
+ if (isTestFile(context.filename)) {
22
+ return {};
23
+ }
24
+ return undefined;
25
+ };
26
+
27
+ /**
28
+ * Helper function to skip rules for example files
29
+ * @param context The ESLint rule context
30
+ * @returns An empty RuleListener if the file is an example file, undefined otherwise
31
+ */
32
+ export const skipForExampleFiles = context => {
33
+ if (context.filename.includes('example')) {
34
+ return {};
35
+ }
36
+ return undefined;
37
+ };
package/dist/esm/index.js CHANGED
@@ -14,6 +14,7 @@ import ensureFeatureFlagPrefix from './rules/ensure-feature-flag-prefix';
14
14
  import ensureCriticalDependencyResolutions from './rules/ensure-critical-dependency-resolutions';
15
15
  import ensureValidPlatformYarnProtocolUsage from './rules/ensure-valid-platform-yarn-protocol-usage';
16
16
  import ensureValidBinValues from './rules/ensure-valid-bin-values';
17
+ import ensureNoPrivateDependencies from './rules/ensure-no-private-dependencies';
17
18
  import expandBorderShorthand from './rules/compiled/expand-border-shorthand';
18
19
  import noInvalidStorybookDecoratorUsage from './rules/no-invalid-storybook-decorator-usage';
19
20
  import ensurePublishValid from './rules/ensure-publish-valid';
@@ -29,6 +30,26 @@ import useEntrypointsInExamples from './rules/use-entrypoints-in-examples';
29
30
  import useRecommendedUtils from './rules/feature-gating/use-recommended-utils';
30
31
  import expandBackgroundShorthand from './rules/compiled/expand-background-shorthand';
31
32
  import expandSpacingShorthand from './rules/compiled/expand-spacing-shorthand';
33
+ import noSparseCheckout from './rules/no-sparse-checkout';
34
+ import noDirectDocumentUsage from './rules/no-direct-document-usage';
35
+ import { join, normalize } from 'node:path';
36
+ import { readFileSync } from 'node:fs';
37
+ var jiraRoot;
38
+ try {
39
+ var findUp = require('find-up');
40
+ findUp.sync(function (dir) {
41
+ var productsJsonPath = join(dir, 'products.json');
42
+ if (findUp.sync.exists(productsJsonPath)) {
43
+ var productJson = JSON.parse(readFileSync(productsJsonPath, 'utf-8'));
44
+ if (productJson.Jira) {
45
+ jiraRoot = normalize(join(dir, productJson.Jira.path));
46
+ return findUp.stop;
47
+ }
48
+ }
49
+ });
50
+ } catch (_unused) {
51
+ // we aren't running inside of AFM, so we can ignore this.
52
+ }
32
53
  var packageJson = require('@atlaskit/eslint-plugin-platform/package.json');
33
54
  var rules = {
34
55
  'ensure-feature-flag-registration': ensureFeatureFlagRegistration,
@@ -39,6 +60,7 @@ var rules = {
39
60
  'ensure-critical-dependency-resolutions': ensureCriticalDependencyResolutions,
40
61
  'ensure-valid-platform-yarn-protocol-usage': ensureValidPlatformYarnProtocolUsage,
41
62
  'ensure-valid-bin-values': ensureValidBinValues,
63
+ 'ensure-no-private-dependencies': ensureNoPrivateDependencies,
42
64
  'expand-border-shorthand': expandBorderShorthand,
43
65
  'expand-background-shorthand': expandBackgroundShorthand,
44
66
  'expand-spacing-shorthand': expandSpacingShorthand,
@@ -56,7 +78,9 @@ var rules = {
56
78
  'prefer-fg': preferFG,
57
79
  'no-alias': noAlias,
58
80
  'use-entrypoints-in-examples': useEntrypointsInExamples,
59
- 'use-recommended-utils': useRecommendedUtils
81
+ 'use-recommended-utils': useRecommendedUtils,
82
+ 'no-sparse-checkout': noSparseCheckout,
83
+ 'no-direct-document-usage': noDirectDocumentUsage
60
84
  };
61
85
  var commonConfig = {
62
86
  '@atlaskit/platform/ensure-test-runner-arguments': 'error',
@@ -65,6 +89,7 @@ var commonConfig = {
65
89
  '@atlaskit/platform/no-invalid-storybook-decorator-usage': 'error',
66
90
  '@atlaskit/platform/ensure-atlassian-team': 'error',
67
91
  '@atlaskit/platform/no-module-level-eval-nav4': 'error',
92
+ '@atlaskit/platform/no-direct-document-usage': 'warn',
68
93
  // Compiled: rules that are not included via `@compiled/recommended
69
94
  '@atlaskit/platform/expand-border-shorthand': 'error',
70
95
  '@atlaskit/platform/expand-background-shorthand': 'error',
@@ -93,6 +118,7 @@ var recommendedRules = _objectSpread(_objectSpread({}, commonConfig), {}, {
93
118
  var jiraRules = commonConfig;
94
119
  var jsonPrefix = '/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ';
95
120
  var jsonPrefixForFlatConfig = '/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, no-template-curly-in-string */ module.exports = ';
121
+ var jsonPrefixForJira = 'module.exports = ';
96
122
  var name = packageJson.name,
97
123
  version = packageJson.version;
98
124
  var plugin = {
@@ -139,7 +165,14 @@ var plugin = {
139
165
  },
140
166
  processors: {
141
167
  'package-json-processor': {
142
- preprocess: function preprocess(source) {
168
+ preprocess: function preprocess(source, filename) {
169
+ // we only need to check for jiraRoot because it uses a different
170
+ // ESLint version and produces fake errors due to how this processor handles JSON
171
+ if (jiraRoot && filename.startsWith(jiraRoot)) {
172
+ // augment the json into a js file
173
+ return [jsonPrefixForJira + source.trim()];
174
+ }
175
+
143
176
  // augment the json into a js file
144
177
  return [jsonPrefix + source.trim()];
145
178
  },
@@ -162,7 +195,13 @@ var plugin = {
162
195
  // This processor is used for ESLint FlatConfig,
163
196
  // once we roll out FlatConfig, we can remove the above processor
164
197
  'package-json-processor-for-flat-config': {
165
- preprocess: function preprocess(source) {
198
+ // we only need to check for jiraRoot because it uses a different
199
+ // ESLint version and produces fake errors due to how this processor handles JSON
200
+ preprocess: function preprocess(source, filename) {
201
+ if (jiraRoot && filename.startsWith(jiraRoot)) {
202
+ // augment the json into a js file
203
+ return [jsonPrefixForJira + source.trim()];
204
+ }
166
205
  // augment the json into a js file
167
206
  return [jsonPrefixForFlatConfig + source.trim()];
168
207
  },
@@ -6,6 +6,9 @@ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t =
6
6
  import path from 'path';
7
7
  import { getMetadataForFilename } from '../util/registration-utils';
8
8
  var exportsValidationExceptions = {
9
+ '@af/yarn-workspace': {
10
+ ignoredAfExportKeys: ['./lock-parser']
11
+ },
9
12
  '@atlaskit/tokens': {
10
13
  ignoredAfExportKeys: ['./babel-plugin']
11
14
  },
@@ -0,0 +1,96 @@
1
+ import _asyncToGenerator from "@babel/runtime/helpers/asyncToGenerator";
2
+ import _regeneratorRuntime from "@babel/runtime/regenerator";
3
+ function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
4
+ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
5
+ function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
6
+ // eslint-disable-next-line import/no-extraneous-dependencies
7
+
8
+ import { getObjectPropertyAsObject, getObjectPropertyAsLiteral } from '../util/handle-ast-object';
9
+ import { getPackagesSync } from '@manypkg/get-packages';
10
+ import { findRootSync } from '@manypkg/find-root';
11
+ var root = findRootSync(process.cwd());
12
+ var pkgs = getPackagesSync(root).packages;
13
+ var pkgMap = new Map(pkgs.map(function (pkg) {
14
+ return [pkg.packageJson.name, pkg];
15
+ }));
16
+ var rule = {
17
+ meta: {
18
+ type: 'problem',
19
+ docs: {
20
+ description: "Ensures that private dependencies are not used in published packages.",
21
+ recommended: true
22
+ },
23
+ hasSuggestions: false,
24
+ messages: {
25
+ invalidPrivateDependency: "Published package has private dependency '{{ pkgName }}'. To resolve this error, remove the private dependency or set this package to private."
26
+ }
27
+ },
28
+ create: function create(context) {
29
+ return {
30
+ ObjectExpression: function () {
31
+ var _ObjectExpression = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(node) {
32
+ var isPrivatePkg, dependencies, peerDependencies, _i, _arr, obj, _iterator, _step, p, key, _pkgMap$get, isPrivateDependency;
33
+ return _regeneratorRuntime.wrap(function _callee$(_context) {
34
+ while (1) switch (_context.prev = _context.next) {
35
+ case 0:
36
+ if (!(!context.filename.endsWith('package.json') || node.type !== 'ObjectExpression')) {
37
+ _context.next = 2;
38
+ break;
39
+ }
40
+ return _context.abrupt("return");
41
+ case 2:
42
+ // Private dependencies can be used in private packages
43
+ isPrivatePkg = getObjectPropertyAsLiteral(node, 'private') === true;
44
+ if (!(isPrivatePkg === true)) {
45
+ _context.next = 5;
46
+ break;
47
+ }
48
+ return _context.abrupt("return");
49
+ case 5:
50
+ // Check for private dependencies in dependencies and peerDependencies
51
+ // Note: devDependencies are not checked here as they don't end up in consumer lockfiles
52
+ dependencies = getObjectPropertyAsObject(node, 'dependencies');
53
+ peerDependencies = getObjectPropertyAsObject(node, 'peerDependencies');
54
+ for (_i = 0, _arr = [dependencies, peerDependencies]; _i < _arr.length; _i++) {
55
+ obj = _arr[_i];
56
+ _iterator = _createForOfIteratorHelper((obj === null || obj === void 0 ? void 0 : obj.properties) || []);
57
+ try {
58
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
59
+ p = _step.value;
60
+ if (p.type === 'Property' && p.key.type === 'Literal') {
61
+ key = p.key.value;
62
+ if (typeof key === 'string' && pkgMap.has(key)) {
63
+ isPrivateDependency = ((_pkgMap$get = pkgMap.get(key)) === null || _pkgMap$get === void 0 ? void 0 : _pkgMap$get.packageJson.private) === true;
64
+ if (isPrivateDependency) {
65
+ context.report({
66
+ node: node,
67
+ messageId: 'invalidPrivateDependency',
68
+ data: {
69
+ pkgName: key
70
+ }
71
+ });
72
+ }
73
+ }
74
+ }
75
+ }
76
+ } catch (err) {
77
+ _iterator.e(err);
78
+ } finally {
79
+ _iterator.f();
80
+ }
81
+ }
82
+ case 8:
83
+ case "end":
84
+ return _context.stop();
85
+ }
86
+ }, _callee);
87
+ }));
88
+ function ObjectExpression(_x) {
89
+ return _ObjectExpression.apply(this, arguments);
90
+ }
91
+ return ObjectExpression;
92
+ }()
93
+ };
94
+ }
95
+ };
96
+ export default rule;
@@ -3,8 +3,7 @@ function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r)
3
3
  function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
4
4
  // eslint-disable-next-line import/no-extraneous-dependencies
5
5
 
6
- import { getObjectPropertyAsObject, getObjectPropertyAsLiteral } from '../util/handle-ast-object';
7
- var workspaceProtocolRegex = /^workspace:[\^~\*]$/;
6
+ import { getObjectPropertyAsObject } from '../util/handle-ast-object';
8
7
  var rootProtocolRegex = /^root:[\^~\*]$/;
9
8
 
10
9
  /**
@@ -17,7 +16,8 @@ function getYarnProtocolsUsed(node) {
17
16
  };
18
17
  var dependencies = getObjectPropertyAsObject(node, 'dependencies');
19
18
  var devDependencies = getObjectPropertyAsObject(node, 'devDependencies');
20
- for (var _i = 0, _arr = [dependencies, devDependencies]; _i < _arr.length; _i++) {
19
+ var peerDependencies = getObjectPropertyAsObject(node, 'peerDependencies');
20
+ for (var _i = 0, _arr = [dependencies, devDependencies, peerDependencies]; _i < _arr.length; _i++) {
21
21
  var obj = _arr[_i];
22
22
  var _iterator = _createForOfIteratorHelper((obj === null || obj === void 0 ? void 0 : obj.properties) || []),
23
23
  _step;
@@ -26,9 +26,6 @@ function getYarnProtocolsUsed(node) {
26
26
  var p = _step.value;
27
27
  if (p.type === 'Property' && p.value.type === 'Literal') {
28
28
  if (typeof p.value.value === 'string') {
29
- if (workspaceProtocolRegex.test(p.value.value)) {
30
- protocolsUsed.workspace = true;
31
- }
32
29
  if (rootProtocolRegex.test(p.value.value)) {
33
30
  protocolsUsed.root = true;
34
31
  }
@@ -52,7 +49,7 @@ var rule = {
52
49
  },
53
50
  hasSuggestions: false,
54
51
  messages: {
55
- invalidWorkspaceProtocolUsage: "The 'workspace:' protocol is not allowed in public packages. To resolve this error, either set the package to private or replace the 'workspace:' protocol with specific package versions (e.g. '^1.0.0').",
52
+ invalidWorkspaceProtocolUsage: "The 'workspace:^'protocol is Used. To resolve this error, please use the 'workspace:*' protocol instead.",
56
53
  invalidRootProtocolUsage: "The 'root:' protocol is not allowed in platform packages. To resolve this error, replace the 'root:' protocol with specific package versions (e.g. '^1.0.0')."
57
54
  }
58
55
  },
@@ -71,15 +68,6 @@ var rule = {
71
68
  messageId: 'invalidRootProtocolUsage'
72
69
  });
73
70
  }
74
-
75
- // The 'workspace:' protocol can not be used in public packages
76
- var isPrivatePackage = getObjectPropertyAsLiteral(node, 'private') === true;
77
- if (!isPrivatePackage && yarnProtocolsUsed.workspace) {
78
- context.report({
79
- node: node,
80
- messageId: 'invalidWorkspaceProtocolUsage'
81
- });
82
- }
83
71
  }
84
72
  };
85
73
  }
@@ -49,7 +49,7 @@ var rule = {
49
49
  url: 'https://stash.atlassian.com/projects/ATLASSIAN/repos/atlassian-frontend-monorepo/browse/platform/packages/platform/eslint-plugin/src/rules/no-preconditioning/README.md'
50
50
  },
51
51
  messages: {
52
- useConfig: 'Do not precondition gates or experiments with another gate. Configure this in Statsig instead to reduce unnecessary code and simplify cleanup.',
52
+ useConfig: 'Do not precondition gates or experiments with another gate. Configure this in Statsig instead to reduce unnecessary code, simplify cleanup and to ensure accurate exposures in Statsig.',
53
53
  incorrectExposure: 'Evaluate gates or experiments at the end of your logical expression to ensure exposure is tracked correctly.'
54
54
  }
55
55
  },
@@ -0,0 +1,97 @@
1
+ import { skipForExampleFiles, skipForTestFiles } from '../util/file-exclusions';
2
+ var rule = {
3
+ meta: {
4
+ type: 'problem',
5
+ docs: {
6
+ description: 'Enforce using getDocument from @atlaskit/browser-apis instead of direct document usage',
7
+ recommended: true
8
+ },
9
+ messages: {
10
+ useGetDocument: 'Use getDocument from @atlaskit/browser-apis instead of direct document usage'
11
+ },
12
+ schema: []
13
+ },
14
+ create: function create(context) {
15
+ var hasGetDocumentImport = false;
16
+ var filename = context.filename;
17
+
18
+ // Skip test files
19
+ var skipResult = skipForTestFiles(context);
20
+ if (skipResult) {
21
+ return skipResult;
22
+ }
23
+
24
+ // Skip example files
25
+ var skipResult2 = skipForExampleFiles(context);
26
+ if (skipResult2) {
27
+ return skipResult2;
28
+ }
29
+
30
+ // Skip the getDocument.ts file itself
31
+ if (filename.endsWith('getDocument.ts')) {
32
+ return {};
33
+ }
34
+ return {
35
+ ImportDeclaration: function ImportDeclaration(node) {
36
+ if (node.source.value === '@atlaskit/browser-apis' && node.specifiers.some(function (specifier) {
37
+ return specifier.type === 'ImportSpecifier' && specifier.imported.name === 'getDocument';
38
+ })) {
39
+ hasGetDocumentImport = true;
40
+ }
41
+ },
42
+ Identifier: function Identifier(node) {
43
+ if (node.name === 'document' && !hasGetDocumentImport) {
44
+ var parent = node.parent;
45
+
46
+ // Skip if 'document' is used as a property key in an object literal
47
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.key === node) {
48
+ return;
49
+ }
50
+
51
+ // Skip if 'document' is used as a shorthand property value
52
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'Property' && parent.value === node && parent.shorthand) {
53
+ return;
54
+ }
55
+
56
+ // Skip if 'document' is used as a property being accessed in a member expression
57
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MemberExpression' && parent.property === node && !parent.computed) {
58
+ return;
59
+ }
60
+
61
+ // Skip if 'document' is being declared as a variable
62
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'VariableDeclarator' && parent.id === node) {
63
+ return;
64
+ }
65
+
66
+ // Skip if 'document' is a function name
67
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'FunctionDeclaration' && 'id' in parent && parent.id === node) {
68
+ return;
69
+ }
70
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'FunctionExpression' && 'id' in parent && parent.id === node) {
71
+ return;
72
+ }
73
+
74
+ // Skip if 'document' is a method name in a class or object
75
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'MethodDefinition' && parent.key === node) {
76
+ return;
77
+ }
78
+
79
+ // Skip if 'document' is being assigned to (shadowing the global)
80
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'AssignmentExpression' && parent.left === node) {
81
+ return;
82
+ }
83
+
84
+ // Skip if 'document' is in a destructuring pattern (could be destructuring from an object)
85
+ if ((parent === null || parent === void 0 ? void 0 : parent.type) === 'ObjectPattern' || (parent === null || parent === void 0 ? void 0 : parent.type) === 'ArrayPattern') {
86
+ return;
87
+ }
88
+ context.report({
89
+ node: node,
90
+ messageId: 'useGetDocument'
91
+ });
92
+ }
93
+ }
94
+ };
95
+ }
96
+ };
97
+ export default rule;