@flarum/cli 3.0.11 → 3.0.13

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 (76) hide show
  1. package/README.md +33 -1
  2. package/bin/libgit2.1.5.dylib +0 -0
  3. package/bin/splitsh-lite-darwin-arm64 +0 -0
  4. package/boilerplate/skeleton/extension/composer.json +4 -0
  5. package/boilerplate/skeleton/extension/js/package.json +5 -5
  6. package/boilerplate/skeleton/extension/js/tsconfig.json +3 -0
  7. package/boilerplate/skeleton/extension/js/tsconfig.test.json +1 -0
  8. package/boilerplate/skeleton/extension/phpstan.neon +0 -1
  9. package/boilerplate/skeleton/extension/tests/phpunit.integration.xml +1 -0
  10. package/boilerplate/skeleton/extension/tests/phpunit.unit.xml +2 -1
  11. package/boilerplate/stubs/backend/advanced-api-resource.php +3 -3
  12. package/boilerplate/stubs/backend/model-factory.php +17 -0
  13. package/boilerplate/stubs/backend/model.php +3 -0
  14. package/lib/base-command.d.ts +21 -3
  15. package/lib/base-command.js +52 -5
  16. package/lib/commands/make/backend/model.js +10 -0
  17. package/lib/commands/monorepo/split.js +1 -1
  18. package/lib/commands/upgrade/2.0.d.ts +43 -0
  19. package/lib/commands/upgrade/2.0.js +128 -2
  20. package/lib/steps/gen-ext-scaffolder.d.ts +5 -0
  21. package/lib/steps/gen-ext-scaffolder.js +17 -2
  22. package/lib/steps/monorepo/split.d.ts +2 -1
  23. package/lib/steps/monorepo/split.js +20 -5
  24. package/lib/steps/stubs/backend/advanced-api-resource.js +1 -1
  25. package/lib/steps/stubs/backend/model-factory.d.ts +24 -0
  26. package/lib/steps/stubs/backend/model-factory.js +33 -0
  27. package/lib/steps/upgrade/twopointoh/backend/email-views.js +22 -30
  28. package/lib/steps/upgrade/twopointoh/backend/extension-models.d.ts +30 -0
  29. package/lib/steps/upgrade/twopointoh/backend/extension-models.js +34 -0
  30. package/lib/steps/upgrade/twopointoh/backend/json-api.d.ts +6 -0
  31. package/lib/steps/upgrade/twopointoh/backend/json-api.js +14 -0
  32. package/lib/steps/upgrade/twopointoh/backend/misc.d.ts +6 -0
  33. package/lib/steps/upgrade/twopointoh/backend/misc.js +19 -7
  34. package/lib/steps/upgrade/twopointoh/backend/model-factories.d.ts +18 -0
  35. package/lib/steps/upgrade/twopointoh/backend/model-factories.js +73 -0
  36. package/lib/steps/upgrade/twopointoh/backend/phpunit-xml.d.ts +8 -0
  37. package/lib/steps/upgrade/twopointoh/backend/phpunit-xml.js +33 -0
  38. package/lib/steps/upgrade/twopointoh/backend/phpunit.d.ts +2 -0
  39. package/lib/steps/upgrade/twopointoh/backend/phpunit.js +34 -21
  40. package/lib/steps/upgrade/twopointoh/backend/search.d.ts +9 -0
  41. package/lib/steps/upgrade/twopointoh/backend/search.js +28 -10
  42. package/lib/steps/upgrade/twopointoh/base.d.ts +38 -0
  43. package/lib/steps/upgrade/twopointoh/base.js +122 -24
  44. package/lib/steps/upgrade/twopointoh/dependencies.d.ts +58 -1
  45. package/lib/steps/upgrade/twopointoh/dependencies.js +343 -15
  46. package/lib/steps/upgrade/twopointoh/frontend/admin-extender.d.ts +86 -0
  47. package/lib/steps/upgrade/twopointoh/frontend/admin-extender.js +842 -0
  48. package/lib/steps/upgrade/twopointoh/frontend/code-splitting/usage-of-lazy-modules.js +110 -18
  49. package/lib/steps/upgrade/twopointoh/frontend/export-registry/import-ext.js +13 -16
  50. package/lib/steps/upgrade/twopointoh/frontend/misc.d.ts +23 -0
  51. package/lib/steps/upgrade/twopointoh/frontend/misc.js +147 -8
  52. package/lib/steps/upgrade/twopointoh/infra.d.ts +16 -1
  53. package/lib/steps/upgrade/twopointoh/infra.js +87 -5
  54. package/lib/steps/upgrade/twopointoh/step-failures.d.ts +32 -0
  55. package/lib/steps/upgrade/twopointoh/step-failures.js +54 -0
  56. package/lib/steps/upgrade/twopointoh/todos.d.ts +22 -0
  57. package/lib/steps/upgrade/twopointoh/todos.js +57 -0
  58. package/lib/steps/upgrade/twopointoh/typescript-4-9.d.ts +12 -0
  59. package/lib/steps/upgrade/twopointoh/typescript-4-9.js +200 -0
  60. package/lib/utils/ast.js +5 -10
  61. package/lib/utils/babel-ts.d.ts +9 -0
  62. package/lib/utils/babel-ts.js +18 -0
  63. package/lib/utils/composer.d.ts +5 -0
  64. package/lib/utils/composer.js +10 -1
  65. package/lib/utils/terminal.d.ts +13 -0
  66. package/lib/utils/terminal.js +26 -0
  67. package/oclif.manifest.json +1 -1
  68. package/package.json +1 -1
  69. package/php-subsystem/index.php +12 -0
  70. package/php-subsystem/src/NodeUtil.php +19 -9
  71. package/php-subsystem/src/NodeVisitors/AddExtender.php +49 -1
  72. package/php-subsystem/src/Upgrade/TwoPointOh/JsonApi.php +2 -20
  73. package/php-subsystem/src/Upgrade/TwoPointOh/Misc.php +13 -17
  74. package/php-subsystem/src/Upgrade/TwoPointOh/ModelFactories.php +943 -0
  75. package/php-subsystem/src/Upgrade/TwoPointOh/PhpUnit.php +476 -71
  76. package/php-subsystem/src/Upgrade/TwoPointOh/Search.php +97 -13
@@ -0,0 +1,18 @@
1
+ import { BaseUpgradeStep, GitCommit, Replacement } from '../base';
2
+ /**
3
+ * Give each of the extension's models a factory, written from what its
4
+ * migrations say about the model's table, so that tests naming the model in
5
+ * prepareDatabase() need only give the columns they care about.
6
+ */
7
+ export default class ModelFactories extends BaseUpgradeStep {
8
+ type: string;
9
+ /** The factories this step wrote. */
10
+ protected written: string[];
11
+ private extension;
12
+ replacements(file: string): Replacement[];
13
+ targets(): string[];
14
+ gitCommit(): GitCommit;
15
+ pauseMessage(): string;
16
+ addFactory(): Replacement;
17
+ private found;
18
+ }
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
5
+ const fs_1 = tslib_1.__importDefault(require("fs"));
6
+ const path_1 = tslib_1.__importDefault(require("path"));
7
+ const base_1 = require("../base");
8
+ const extension_models_1 = require("./extension-models");
9
+ /**
10
+ * Give each of the extension's models a factory, written from what its
11
+ * migrations say about the model's table, so that tests naming the model in
12
+ * prepareDatabase() need only give the columns they care about.
13
+ */
14
+ class ModelFactories extends base_1.BaseUpgradeStep {
15
+ constructor() {
16
+ super(...arguments);
17
+ this.type = 'Model factories for tests';
18
+ /** The factories this step wrote. */
19
+ this.written = [];
20
+ this.extension = null;
21
+ }
22
+ replacements(file) {
23
+ return file.endsWith('.php') ? [this.addFactory()] : [];
24
+ }
25
+ targets() {
26
+ return ['src/**/*.php'];
27
+ }
28
+ gitCommit() {
29
+ return {
30
+ message: 'chore(2.0): model factories for tests',
31
+ description: "Flarum 2.0 tests take the columns they leave out from the model's factory.",
32
+ };
33
+ }
34
+ pauseMessage() {
35
+ const link = 'https://docs.flarum.org/2.x/extend/testing#model-factories';
36
+ return [
37
+ `Each model has a factory now. Written by this step: ${this.written.join(', ') || 'none'}.`,
38
+ 'Tests that give prepareDatabase() a model class, rather than its table, take the columns they leave out from it.',
39
+ 'Look for the @TODO comments on columns the migrations gave no default.',
40
+ chalk_1.default.underline(link),
41
+ ].join('\n ');
42
+ }
43
+ addFactory() {
44
+ return (file, code) => {
45
+ var _a;
46
+ const { models, byTable, tables } = this.found();
47
+ const model = models.find((candidate) => candidate.file === file);
48
+ if (!model)
49
+ return null;
50
+ const factory = path_1.default.posix.join(path_1.default.posix.dirname(file), `${model.class.split('\\').pop()}Factory.php`);
51
+ const hasFactoryClass = fs_1.default.existsSync(path_1.default.join(this.root, factory));
52
+ if (model.hasFactory && hasFactoryClass)
53
+ return null;
54
+ const result = this.php.run('upgrade.2-0.model-factory', {
55
+ file,
56
+ code,
57
+ data: { columns: (_a = tables[model.table]) !== null && _a !== void 0 ? _a : null, models: byTable },
58
+ });
59
+ // A factory the extension already has is its own.
60
+ if (hasFactoryClass) {
61
+ return { updated: result.code };
62
+ }
63
+ this.written.push(factory);
64
+ return { updated: result.code, newFiles: [{ path: factory, code: result.factory }] };
65
+ };
66
+ }
67
+ found() {
68
+ var _a;
69
+ (_a = this.extension) !== null && _a !== void 0 ? _a : (this.extension = Object.assign(Object.assign({}, (0, extension_models_1.extensionModels)(this.root, this.php)), { tables: (0, extension_models_1.migrationTables)(this.root, this.php) }));
70
+ return this.extension;
71
+ }
72
+ }
73
+ exports.default = ModelFactories;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Convert a PHPUnit 9-era config to the shape the CLI scaffolds for 2.x
3
+ * extensions: schema resolved from the vendored phpunit, the attributes
4
+ * PHPUnit 10 removed dropped or renamed, coverage's include list moved to
5
+ * <source>, the Mockery listener block removed, and warning details enabled
6
+ * so flarum/testing's query guard is visible in the output.
7
+ */
8
+ export declare function modernizePhpunitXml(file: string, code: string): string;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.modernizePhpunitXml = void 0;
4
+ /**
5
+ * Convert a PHPUnit 9-era config to the shape the CLI scaffolds for 2.x
6
+ * extensions: schema resolved from the vendored phpunit, the attributes
7
+ * PHPUnit 10 removed dropped or renamed, coverage's include list moved to
8
+ * <source>, the Mockery listener block removed, and warning details enabled
9
+ * so flarum/testing's query guard is visible in the output.
10
+ */
11
+ function modernizePhpunitXml(file, code) {
12
+ // The schema path is relative to the config file's own directory.
13
+ const prefix = '../'.repeat(file.split('/').length - 1);
14
+ let updated = code.replace(/xsi:noNamespaceSchemaLocation="[^"]*"/, `xsi:noNamespaceSchemaLocation="${prefix}vendor/phpunit/phpunit/phpunit.xsd"`);
15
+ // Attributes removed in PHPUnit 10.
16
+ updated = updated.replace(/[\t ]*(?:convert(?:Deprecations|Errors|Notices|Warnings)ToExceptions|forceCoversAnnotation|verbose|printerClass)="[^"]*"\r?\n/g, '');
17
+ updated = updated.replace(/backupStaticAttributes=/g, 'backupStaticProperties=');
18
+ // New settings, inserted next to their neighbours in the scaffolded order.
19
+ if (!updated.includes('cacheDirectory=')) {
20
+ updated = updated.replace(/(\n([\t ]*)backupGlobals="[^"]*")/, '$1\n$2cacheDirectory=".phpunit.cache"');
21
+ }
22
+ if (!updated.includes('displayDetailsOnTestsThatTriggerWarnings=')) {
23
+ updated = updated.replace(/(\n([\t ]*)colors="[^"]*")/, '$1\n$2displayDetailsOnTestsThatTriggerWarnings="true"');
24
+ }
25
+ // The include list lives in <source> now; coverage configuration as it
26
+ // existed in 9.x is gone.
27
+ updated = updated.replace(/<coverage[^>]*>/, '<source>').replace(/<\/coverage>/, '</source>');
28
+ // Test listeners were removed in PHPUnit 10 (Mockery integration works
29
+ // without one).
30
+ updated = updated.replace(/[\t ]*<listeners>[\S\s]*?<\/listeners>\r?\n?/, '');
31
+ return updated;
32
+ }
33
+ exports.modernizePhpunitXml = modernizePhpunitXml;
@@ -1,6 +1,8 @@
1
1
  import { BaseUpgradeStep, GitCommit, Replacement } from '../base';
2
2
  export default class PhpUnit extends BaseUpgradeStep {
3
3
  type: string;
4
+ /** Core's models and the extension's, by table, for prepareDatabase() to name. */
5
+ private models;
4
6
  replacements(file: string): Replacement[];
5
7
  targets(): string[];
6
8
  gitCommit(): GitCommit;
@@ -3,44 +3,57 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const base_1 = require("../base");
5
5
  const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const phpunit_xml_1 = require("./phpunit-xml");
7
+ const extension_models_1 = require("./extension-models");
6
8
  class PhpUnit extends base_1.BaseUpgradeStep {
7
9
  constructor() {
8
10
  super(...arguments);
9
- this.type = 'PHPUnit 9 to 11 changes';
11
+ this.type = 'PHPUnit 9 to 12 changes';
12
+ /** Core's models and the extension's, by table, for prepareDatabase() to name. */
13
+ this.models = null;
10
14
  }
11
15
  replacements(file) {
12
- if (!file.endsWith('.php'))
13
- return [];
14
- return [
15
- (_file, code) => ({
16
- updated: this.php.run('upgrade.2-0.phpunit', { file, code }).code,
17
- }),
18
- (file, code) => {
19
- if (!file.endsWith('.xml'))
20
- return null;
21
- return {
22
- updated: code.replace('xsi:noNamespaceSchemaLocation="([^"]+)"', 'xsi:noNamespaceSchemaLocation="../vendor/phpunit/phpunit/phpunit.xsd"'),
23
- };
24
- },
25
- ];
16
+ if (file.endsWith('.php')) {
17
+ return [
18
+ (_file, code) => {
19
+ var _a;
20
+ (_a = this.models) !== null && _a !== void 0 ? _a : (this.models = (0, extension_models_1.extensionModels)(this.root, this.php).byTable);
21
+ return {
22
+ updated: this.php.run('upgrade.2-0.phpunit', { file, code, data: { models: this.models } }).code,
23
+ };
24
+ },
25
+ ];
26
+ }
27
+ // The XML rewrite previously sat behind the .php guard above (making it
28
+ // unreachable) and used String.replace with regex syntax in a string
29
+ // (matching nothing) — every upgraded extension kept its 9.3-era config.
30
+ if (/(^|\/)phpunit(\.[\w-]+)?\.xml$/.test(file)) {
31
+ return [
32
+ (xmlFile, code) => ({
33
+ updated: (0, phpunit_xml_1.modernizePhpunitXml)(xmlFile, code),
34
+ }),
35
+ ];
36
+ }
37
+ return [];
26
38
  }
27
39
  targets() {
28
- return ['tests/**/*'];
40
+ return ['tests/**/*', 'phpunit.xml', 'phpunit.*.xml'];
29
41
  }
30
42
  gitCommit() {
31
43
  return {
32
- message: 'chore(2.0): Backend tests + PHPUnit 9 to 11 changes',
33
- description: 'Flarum 2.0 uses PHPUnit 11 and encourages use of model factories for easier cross-database testing.',
44
+ message: 'chore(2.0): Backend tests + PHPUnit 9 to 12 changes',
45
+ description: 'Flarum 2.0 uses PHPUnit 12 and encourages use of model factories for easier cross-database testing.',
34
46
  };
35
47
  }
36
48
  pauseMessage() {
37
49
  const links = [
38
50
  'https://github.com/sebastianbergmann/phpunit/blob/9.6/DEPRECATIONS.md',
39
51
  'https://github.com/sebastianbergmann/phpunit/blob/10.5/DEPRECATIONS.md',
40
- 'https://github.com/sebastianbergmann/phpunit/blob/11.3.0/DEPRECATIONS.md',
52
+ 'https://github.com/sebastianbergmann/phpunit/blob/11.5/DEPRECATIONS.md',
53
+ 'https://github.com/sebastianbergmann/phpunit/blob/12.5/DEPRECATIONS.md',
41
54
  ];
42
- const dbLink = 'http://localhost:3000/extend/testing#model-factories';
43
- return `Flarum 2.0 uses PHPUnit 11. The tool has applied the most significant changes, but you might still run into other deprecations.
55
+ const dbLink = 'https://docs.flarum.org/2.x/extend/testing#model-factories';
56
+ return `Flarum 2.0 uses PHPUnit 12. The tool has applied the most significant changes, and left @TODO comments on what it could not, but you might still run into other deprecations.
44
57
  Please refer to the following links for more information:
45
58
  ${links.map((link) => chalk_1.default.underline(link)).join('\n ')}
46
59
 
@@ -21,6 +21,15 @@ export default class Search extends BaseUpgradeStep {
21
21
  protected searchers: Record<string, string>;
22
22
  before(file: string, code: string, _advanced: AdvancedContent): void;
23
23
  replacements(_file: string): Replacement[];
24
+ /**
25
+ * The translations a gambit's stub uses: its key, and a key-value gambit's
26
+ * hint, which the search shows beside it. Only the author can say what the
27
+ * hint should be, so it is left for them to write.
28
+ */
29
+ gambitTranslations(gambit: Gambit): {
30
+ key: string;
31
+ value: string;
32
+ }[];
24
33
  targets(): string[];
25
34
  gitCommit(): GitCommit;
26
35
  pauseMessage(): string;
@@ -9,6 +9,10 @@ const gambit_1 = require("../../../stubs/frontend/gambit");
9
9
  const search_gambit_1 = require("../../../js/search-gambit");
10
10
  const base_2 = require("../../../locale/base");
11
11
  const model_name_1 = require("../../../../utils/model-name");
12
+ const fs_1 = tslib_1.__importDefault(require("fs"));
13
+ const path_1 = tslib_1.__importDefault(require("path"));
14
+ /** A gambit with an is: pattern, such as is:private, rather than a key and value. */
15
+ const isBoolean = (gambit) => gambit.pattern.includes('is:');
12
16
  class Search extends base_1.BaseUpgradeStep {
13
17
  constructor() {
14
18
  super(...arguments);
@@ -116,10 +120,6 @@ class Search extends base_1.BaseUpgradeStep {
116
120
  if (this.gambits.length > 0 && Object.keys(((_a = this.data.collectedData.extendData) === null || _a === void 0 ? void 0 : _a.searchers) || {}).length > 0) {
117
121
  const result = await this.command.runSteps(new step_manager_1.StepManager().silentGroup((steps) => {
118
122
  this.gambits.forEach((gambit, index) => {
119
- let gambitKey = gambit.pattern.replace('is:', '');
120
- if (gambitKey.includes(':')) {
121
- gambitKey = gambitKey.split(':')[0];
122
- }
123
123
  const relatedSearcher = Object.keys(this.data.collectedData.extendData.searchers).find((searcher) => {
124
124
  const filters = this.data.collectedData.extendData.searchers[searcher].filters || [];
125
125
  return filters.some((filter) => {
@@ -130,11 +130,11 @@ class Search extends base_1.BaseUpgradeStep {
130
130
  if (relatedSearcher) {
131
131
  type = (0, model_name_1.pluralKebabCaseModel)(relatedSearcher.split('\\').pop().replace('Searcher', ''));
132
132
  }
133
- steps
133
+ const gambitSteps = steps
134
134
  .namedStep(`gambit-${index}`, new gambit_1.GenerateGambitStub(this.command.STUB_PATH, (0, gen_ext_scaffolder_1.genExtScaffolder)()), {}, [], {
135
135
  frontend: 'common',
136
136
  className: gambit.name,
137
- type: gambit.pattern.includes('is:') ? 'boolean' : 'key-value',
137
+ type: isBoolean(gambit) ? 'boolean' : 'key-value',
138
138
  filterKey: gambit.filterKey,
139
139
  })
140
140
  .step(new search_gambit_1.GenerateSearchGambitExtender(), {}, [
@@ -146,10 +146,9 @@ class Search extends base_1.BaseUpgradeStep {
146
146
  ], {
147
147
  frontend: 'common',
148
148
  modelType: type,
149
- })
150
- .step(new base_2.LocaleStep((0, gen_ext_scaffolder_1.genExtScaffolder)()), {}, [], {
151
- key: `lib.gambits.${gambit.filterKey}.key`,
152
- value: gambitKey,
149
+ });
150
+ this.gambitTranslations(gambit).forEach((translation) => {
151
+ gambitSteps.step(new base_2.LocaleStep((0, gen_ext_scaffolder_1.genExtScaffolder)()), {}, [], translation);
153
152
  });
154
153
  delete this.gambits[index];
155
154
  });
@@ -171,6 +170,25 @@ class Search extends base_1.BaseUpgradeStep {
171
170
  },
172
171
  ];
173
172
  }
173
+ /**
174
+ * The translations a gambit's stub uses: its key, and a key-value gambit's
175
+ * hint, which the search shows beside it. Only the author can say what the
176
+ * hint should be, so it is left for them to write.
177
+ */
178
+ gambitTranslations(gambit) {
179
+ let gambitKey = gambit.pattern.replace('is:', '');
180
+ if (gambitKey.includes(':')) {
181
+ gambitKey = gambitKey.split(':')[0];
182
+ }
183
+ const translations = [{ key: `lib.gambits.${gambit.filterKey}.key`, value: gambitKey }];
184
+ if (!isBoolean(gambit)) {
185
+ const hint = `lib.gambits.${gambit.filterKey}.hint`;
186
+ const locale = fs_1.default.existsSync(path_1.default.join(this.root, 'resources/locale/en.yml')) ? 'resources/locale/en.yml' : 'locale/en.yml';
187
+ translations.push({ key: hint, value: gambitKey });
188
+ this.leaveTodo(locale, `describe what the ${gambitKey} gambit takes in ${hint}, which the search shows beside it.`);
189
+ }
190
+ return translations;
191
+ }
174
192
  targets() {
175
193
  return ['src/**/*', 'extend.php'];
176
194
  }
@@ -8,6 +8,8 @@ import { ModuleImport } from '../../../utils/ast';
8
8
  import { Editor } from 'mem-fs-editor';
9
9
  import BaseCommand from '../../../base-command';
10
10
  import { PhpProvider } from '../../../providers/php-provider';
11
+ import { Failure } from './step-failures';
12
+ import { Todo } from './todos';
11
13
  export type ReplacementResult = {
12
14
  imports?: ImportChange[];
13
15
  newPath?: string | null;
@@ -28,6 +30,26 @@ export type GitCommit = {
28
30
  message: string;
29
31
  description: string;
30
32
  };
33
+ /**
34
+ * What a step did, for a program driving the upgrade.
35
+ */
36
+ export type StepOutcome = {
37
+ status: 'skipped';
38
+ } | {
39
+ status: 'no-changes';
40
+ todos?: Todo[];
41
+ } | {
42
+ status: 'committed';
43
+ commit: {
44
+ sha: string;
45
+ message: string;
46
+ };
47
+ notes: string;
48
+ todos: Todo[];
49
+ } | {
50
+ status: 'failed';
51
+ failures: Failure[];
52
+ };
31
53
  export declare abstract class BaseUpgradeStep implements Step<FlarumProviders> {
32
54
  abstract type: string;
33
55
  composable: boolean;
@@ -37,6 +59,7 @@ export declare abstract class BaseUpgradeStep implements Step<FlarumProviders> {
37
59
  protected command: BaseCommand;
38
60
  protected php: null | PhpProvider;
39
61
  protected step: number;
62
+ get number(): number;
40
63
  protected totalSteps: number;
41
64
  protected forceStep: boolean;
42
65
  protected root: string;
@@ -47,7 +70,22 @@ export declare abstract class BaseUpgradeStep implements Step<FlarumProviders> {
47
70
  abstract replacements(file: string, code: string): Replacement[];
48
71
  abstract gitCommit(): GitCommit;
49
72
  abstract pauseMessage(): string;
73
+ /** Whether the step runs for a check, in a worktree that is thrown away. */
74
+ checking: boolean;
75
+ /** Work this step leaves that no @TODO comment in a file shows. */
76
+ protected followUps: Todo[];
77
+ /**
78
+ * Leave work for the author that the step can't mark with a @TODO comment,
79
+ * such as a file that is missing, or a change it can only point out.
80
+ */
81
+ protected leaveTodo(file: string, text: string): void;
82
+ /** The follow-ups, as lines to print under the step's notes. */
83
+ protected followUpLines(): string[];
50
84
  protected fsEditor: null | Editor;
85
+ /**
86
+ * Unset until the step runs.
87
+ */
88
+ outcome: StepOutcome | null;
51
89
  run(fs: Store, paths: Paths, io: IO, providers: FlarumProviders): Promise<Store>;
52
90
  applyReplacements(file: string, code: string, advanced: AdvancedContent): Promise<ReplacementResult>;
53
91
  ensureImport(file: string, advanced: AdvancedContent, imp: ImportChange): void;