create-pkgbld 1.8.2 → 2.0.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.
package/src/tui.js ADDED
@@ -0,0 +1,167 @@
1
+ import prompts from 'prompts';
2
+
3
+ import { blue, gray, green, red } from '@niceties/ansi';
4
+
5
+ /**
6
+ * @typedef {import('prompts').PromptObject} PromptObject
7
+ * @typedef {import('./types.js').Option} Option
8
+ * @typedef {import('./types.js').OptionsValue} OptionsValue
9
+ * @typedef {{
10
+ * operation: import('./package-operations.js').PreparedPackageOperation,
11
+ * answers: OptionsValue
12
+ * }} PendingPackageOperation
13
+ */
14
+
15
+ export const done = Symbol('done');
16
+ const PACKAGE_PREFIX = '__package__:';
17
+
18
+ /**
19
+ * @param {string} value
20
+ * @param {number} [indent]
21
+ * @param {number} [offset]
22
+ */
23
+ export function pad16plus(value, indent = 4, offset = 3) {
24
+ return value + ''.padEnd(offset - Math.floor((value.length + indent) / 8), '\t');
25
+ }
26
+
27
+ /**
28
+ * Convert an Option leaf into a prompts() configuration.
29
+ *
30
+ * @param {Option} option
31
+ * @param {OptionsValue} answers
32
+ * @returns {PromptObject}
33
+ */
34
+ export function getPromptOption(option, answers) {
35
+ const value = answers[option.field];
36
+ const initialValue = value ?? option.initialValue;
37
+ const type = option.type ?? 'text';
38
+ /** @type {PromptObject} */
39
+ const promptOption = {
40
+ type,
41
+ name: option.field,
42
+ message: option.title,
43
+ initial: /** @type {any} */ (Array.isArray(initialValue) ? initialValue.join(',') : (initialValue ?? '')),
44
+ };
45
+ if (type === 'multiselect') {
46
+ promptOption.choices =
47
+ 'list' in option
48
+ ? option.list.map((/** @type {string} */ item) => ({
49
+ title: item,
50
+ value: item,
51
+ selected: Array.isArray(initialValue) && initialValue.includes(item),
52
+ }))
53
+ : [];
54
+ }
55
+ if (type === 'select') {
56
+ promptOption.choices =
57
+ 'list' in option
58
+ ? option.list.map((/** @type {string} */ item) => ({
59
+ title: item,
60
+ value: item,
61
+ }))
62
+ : [];
63
+ promptOption.initial = /** @type {import('prompts').Choice[]} */ (promptOption.choices).findIndex(
64
+ (/** @type {import('prompts').Choice} */ item) => item.value === promptOption.initial
65
+ );
66
+ }
67
+ return promptOption;
68
+ }
69
+
70
+ /**
71
+ * @param {import('./package-operations.js').PackageView} item
72
+ * @param {PendingPackageOperation | undefined} pending
73
+ */
74
+ function renderPackageLabel(item, pending) {
75
+ const left = pad16plus(item.name);
76
+ if (pending) return `${left}${blue(`[Pending ${pending.operation.effect}]`)}`;
77
+ if (item.state === 'unavailable') return `${left}${red('[Unavailable]')} ${gray(item.error ?? '')}`;
78
+ if (item.state === 'available') return `${left}${gray('[Available]')}`;
79
+ if (item.state === 'applied') return `${left}${blue('[Applied]')}`;
80
+ if (item.state === 'installed-managed') return `${left}${green('[Installed, managed]')}`;
81
+ return `${left}${blue('[Installed, unmanaged]')}`;
82
+ }
83
+
84
+ /**
85
+ * Collect package targets and their answers. Project changes remain unstaged
86
+ * until the caller stages the returned operations.
87
+ *
88
+ * @param {{ packageOperations: Awaited<ReturnType<import('./package-operations.js').openPackageOperations>> }} params
89
+ * @returns {Promise<PendingPackageOperation[]>}
90
+ */
91
+ export async function runInteractiveLoop({ packageOperations }) {
92
+ let cancelled = false;
93
+ function onCancel() {
94
+ cancelled = true;
95
+ }
96
+ /** @type {Map<string, PendingPackageOperation>} */
97
+ const pending = new Map();
98
+
99
+ for (;;) {
100
+ const packageAction = await prompts(
101
+ {
102
+ type: 'select',
103
+ name: 'value',
104
+ message: 'Select a PKG BLD package, Done to execute, Escape to cancel',
105
+ choices: [
106
+ { title: green('Done'), value: /** @type {any} */ (done) },
107
+ ...packageOperations.inventory.map(item => ({
108
+ title: renderPackageLabel(item, pending.get(item.id)),
109
+ value: `${PACKAGE_PREFIX}${item.id}`,
110
+ })),
111
+ ],
112
+ initial: 0,
113
+ },
114
+ { onCancel }
115
+ );
116
+ if (cancelled) throw new Error('cancelled');
117
+ if (packageAction.value === done) return [...pending.values()];
118
+
119
+ if (typeof packageAction.value !== 'string' || !packageAction.value.startsWith(PACKAGE_PREFIX)) continue;
120
+ const id = packageAction.value.slice(PACKAGE_PREFIX.length);
121
+ const item = packageOperations.inventory.find(candidate => candidate.id === id);
122
+ if (!item) continue;
123
+ if (pending.delete(id)) continue;
124
+ if (item.state === 'unavailable') {
125
+ console.log(red(`Package "${item.name}" is unavailable: ${item.error ?? 'not resolvable'}`));
126
+ continue;
127
+ }
128
+
129
+ /** @type {import('./package-operations.js').PackageTarget} */
130
+ let target;
131
+ if (item.state === 'installed-unmanaged') {
132
+ const action = await prompts(
133
+ {
134
+ type: 'select',
135
+ name: 'value',
136
+ message: `Manage ${item.name}`,
137
+ choices: [
138
+ { title: 'Adopt', value: 'managed' },
139
+ { title: 'Remove', value: 'absent' },
140
+ { title: 'Cancel', value: null },
141
+ ],
142
+ },
143
+ { onCancel }
144
+ );
145
+ if (cancelled) throw new Error('cancelled');
146
+ if (action.value === null || action.value === undefined) continue;
147
+ target = action.value;
148
+ } else {
149
+ target = item.state === 'installed-managed' ? 'absent' : 'managed';
150
+ }
151
+
152
+ try {
153
+ const operation = await packageOperations.prepare({ package: id, target });
154
+ /** @type {OptionsValue} */
155
+ const answers = {};
156
+ for (const question of operation.questions) {
157
+ const answer = await prompts(getPromptOption(question, answers), { onCancel });
158
+ if (cancelled) throw new Error('cancelled');
159
+ answers[question.field] = answer[question.field];
160
+ }
161
+ pending.set(id, { operation, answers });
162
+ } catch (/** @type {any} */ error) {
163
+ if (error.message === 'cancelled') throw error;
164
+ console.log(red(`Package "${item.name}" is unavailable: ${error.message ?? String(error)}`));
165
+ }
166
+ }
167
+ }
package/src/types.js ADDED
@@ -0,0 +1,28 @@
1
+ /** @typedef {import('pkgbld/options').PackageJson} PackageJson */
2
+
3
+ /**
4
+ * @typedef {{
5
+ * title: string;
6
+ * field: string;
7
+ * initialValue?: string | string[] | boolean;
8
+ * } & (
9
+ * | { type?: undefined | 'toggle' | 'list' | 'text' }
10
+ * | { type: 'multiselect' | 'select'; list: string[] }
11
+ * )} Option
12
+ */
13
+
14
+ /**
15
+ * @typedef {{
16
+ * readme: string;
17
+ * pkg: PackageJson;
18
+ * mode: 'create' | 'update';
19
+ * }} PkgInfo
20
+ */
21
+
22
+ /**
23
+ * @typedef {{
24
+ * [key: string]: undefined | null | number | boolean | string | string[] | OptionsValue;
25
+ * }} OptionsValue
26
+ */
27
+
28
+ export {};
@@ -0,0 +1,196 @@
1
+ import { readFileSync } from 'node:fs';
2
+ import path from 'node:path';
3
+
4
+ const ABSENT = Symbol('absent');
5
+
6
+ /**
7
+ * Apply target-version update behavior or guarded declarative reconciliation.
8
+ * @param {{
9
+ * previous: import('./registry.js').Extension,
10
+ * target: import('./registry.js').Extension,
11
+ * tree: import('./tree.js').Tree,
12
+ * fromVersion: string,
13
+ * toVersion: string,
14
+ * options?: import('./types.js').OptionsValue,
15
+ * exclude?: string[],
16
+ * reportConflict(conflict: { resource: string, message: string, expected?: unknown, current?: unknown, proposed?: unknown }): void
17
+ * }} params
18
+ */
19
+ export async function runExtensionUpdate({ previous, target, tree, fromVersion, toVersion, options = {}, exclude = [], reportConflict }) {
20
+ const reconcileDeclarative = (/** @type {{ exclude?: string[] }} */ reconcileOptions = {}) => {
21
+ if (!isDeclarative(previous.setup) || !isDeclarative(target.setup)) {
22
+ throw new Error('Declarative reconciliation requires declarative setup in both package versions');
23
+ }
24
+ reconcileSetups(previous, target, tree, reportConflict, [...exclude, ...(reconcileOptions.exclude ?? [])]);
25
+ };
26
+
27
+ if (typeof target.update === 'function') {
28
+ tree.setExtensionBase(target.__baseDir ?? null);
29
+ try {
30
+ await target.update(tree, Object.freeze({ fromVersion, toVersion, reconcileDeclarative, reportConflict }), options);
31
+ } finally {
32
+ tree.setExtensionBase(null);
33
+ }
34
+ return;
35
+ }
36
+
37
+ if (!isDeclarative(previous.setup) || !isDeclarative(target.setup)) {
38
+ throw new Error(`Update from ${fromVersion} to ${toVersion} is unsupported: the target has no update function`);
39
+ }
40
+ reconcileDeclarative();
41
+ }
42
+
43
+ /** @param {unknown} setup */
44
+ function isDeclarative(setup) {
45
+ return Boolean(setup && typeof setup === 'object' && !Array.isArray(setup));
46
+ }
47
+
48
+ /**
49
+ * @param {import('./registry.js').Extension} previous
50
+ * @param {import('./registry.js').Extension} target
51
+ * @param {import('./tree.js').Tree} tree
52
+ * @param {(conflict: any) => void} reportConflict
53
+ * @param {string[]} excluded
54
+ */
55
+ function reconcileSetups(previous, target, tree, reportConflict, excluded) {
56
+ const oldResources = collectResources(/** @type {import('./registry.js').SetupDeclarative} */ (previous.setup), previous);
57
+ const newResources = collectResources(/** @type {import('./registry.js').SetupDeclarative} */ (target.setup), target);
58
+ const excludedSet = new Set(excluded);
59
+ const keys = new Set([...oldResources.keys(), ...newResources.keys()]);
60
+
61
+ for (const key of [...keys].sort()) {
62
+ if (excludedSet.has(key)) continue;
63
+ const oldResource = oldResources.get(key);
64
+ const newResource = newResources.get(key);
65
+ const resource = newResource ?? oldResource;
66
+ if (!resource) continue;
67
+ const oldValue = oldResource?.value ?? ABSENT;
68
+ const newValue = newResource?.value ?? ABSENT;
69
+ const currentValue = readCurrent(resource, tree);
70
+
71
+ if (sameValue(currentValue, oldValue, resource) || sameValue(currentValue, newValue, resource)) {
72
+ if (!sameValue(currentValue, newValue, resource)) applyValue(resource, newValue, tree);
73
+ continue;
74
+ }
75
+ if (sameValue(oldValue, newValue, resource)) continue;
76
+
77
+ reportConflict({
78
+ resource: key,
79
+ expected: externalValue(oldValue),
80
+ current: externalValue(currentValue),
81
+ proposed: externalValue(newValue),
82
+ message: `Resource "${displayResource(resource)}" was changed after the previous package version was applied`,
83
+ });
84
+ applyValue(resource, newValue, tree);
85
+ }
86
+ }
87
+
88
+ /** @param {import('./registry.js').SetupDeclarative} setup @param {import('./registry.js').Extension} extension */
89
+ function collectResources(setup, extension) {
90
+ /** @type {Map<string, any>} */
91
+ const resources = new Map();
92
+ for (const [name, value] of Object.entries(setup.dependencies ?? {})) {
93
+ resources.set(`dependency:dependencies:${name}`, { kind: 'dependency', field: 'dependencies', name, value });
94
+ }
95
+ for (const [name, value] of Object.entries(setup.devDependencies ?? {})) {
96
+ resources.set(`dependency:devDependencies:${name}`, { kind: 'dependency', field: 'devDependencies', name, value });
97
+ }
98
+ for (const [name, value] of Object.entries(setup.scripts ?? {})) {
99
+ resources.set(`script:${name}`, { kind: 'script', name, value });
100
+ }
101
+ for (const [target, source] of Object.entries(setup.files ?? {})) {
102
+ const value = source.startsWith('inline:')
103
+ ? source.slice('inline:'.length)
104
+ : readFileSync(resolveExtensionFile(extension, source), 'utf8');
105
+ resources.set(`file:${target}`, { kind: 'file', path: target, value });
106
+ }
107
+ for (const [name, value] of Object.entries(setup.packageJson ?? {})) {
108
+ resources.set(`package-json:${name}`, { kind: 'package-json', name, value });
109
+ }
110
+ return resources;
111
+ }
112
+
113
+ /** @param {import('./registry.js').Extension} extension @param {string} relativePath */
114
+ function resolveExtensionFile(extension, relativePath) {
115
+ if (!extension.__baseDir) throw new Error(`Cannot resolve extension file "${relativePath}": package base is unavailable`);
116
+ return path.resolve(extension.__baseDir, relativePath);
117
+ }
118
+
119
+ /** @param {any} resource @param {import('./tree.js').Tree} tree */
120
+ function readCurrent(resource, tree) {
121
+ if (resource.kind === 'file') return tree.read(resource.path) ?? ABSENT;
122
+ const pkg = tree.readJson('package.json') ?? {};
123
+ if (resource.kind === 'dependency') return pkg[resource.field]?.[resource.name] ?? ABSENT;
124
+ if (resource.kind === 'script') return pkg.scripts?.[resource.name] ?? ABSENT;
125
+ return pkg[resource.name] ?? ABSENT;
126
+ }
127
+
128
+ /** @param {any} resource @param {unknown} value @param {import('./tree.js').Tree} tree */
129
+ function applyValue(resource, value, tree) {
130
+ if (resource.kind === 'file') {
131
+ if (value === ABSENT) tree.delete(resource.path);
132
+ else tree.write(resource.path, /** @type {string} */ (value));
133
+ return;
134
+ }
135
+ tree.updateJson('package.json', pkg => {
136
+ const container = resource.kind === 'dependency' ? resource.field : resource.kind === 'script' ? 'scripts' : null;
137
+ if (container) {
138
+ if (value === ABSENT) {
139
+ if (pkg[container]) {
140
+ delete pkg[container][resource.name];
141
+ if (Object.keys(pkg[container]).length === 0) delete pkg[container];
142
+ }
143
+ } else {
144
+ pkg[container] ??= {};
145
+ pkg[container][resource.name] = value;
146
+ }
147
+ } else if (value === ABSENT) {
148
+ delete pkg[resource.name];
149
+ } else {
150
+ pkg[resource.name] = value;
151
+ }
152
+ return pkg;
153
+ });
154
+ }
155
+
156
+ /** @param {unknown} left @param {unknown} right @param {any} resource */
157
+ function sameValue(left, right, resource) {
158
+ if (left === ABSENT || right === ABSENT) return left === right;
159
+ if (resource.kind === 'file' && resource.path.endsWith('.json')) {
160
+ try {
161
+ return fingerprint(JSON.parse(/** @type {string} */ (left))) === fingerprint(JSON.parse(/** @type {string} */ (right)));
162
+ } catch {
163
+ return left === right;
164
+ }
165
+ }
166
+ return fingerprint(left) === fingerprint(right);
167
+ }
168
+
169
+ /** @param {unknown} value */
170
+ function fingerprint(value) {
171
+ return JSON.stringify(canonicalize(value));
172
+ }
173
+
174
+ /** @param {unknown} value @returns {unknown} */
175
+ function canonicalize(value) {
176
+ if (Array.isArray(value)) return value.map(canonicalize);
177
+ if (!value || typeof value !== 'object') return value;
178
+ return Object.fromEntries(
179
+ Object.entries(/** @type {Record<string, unknown>} */ (value))
180
+ .sort(([left], [right]) => left.localeCompare(right))
181
+ .map(([key, item]) => [key, canonicalize(item)])
182
+ );
183
+ }
184
+
185
+ /** @param {unknown} value */
186
+ function externalValue(value) {
187
+ return value === ABSENT ? undefined : value;
188
+ }
189
+
190
+ /** @param {any} resource */
191
+ function displayResource(resource) {
192
+ if (resource.kind === 'file') return resource.path;
193
+ if (resource.kind === 'dependency') return `${resource.field}.${resource.name}`;
194
+ if (resource.kind === 'script') return `scripts.${resource.name}`;
195
+ return `package.json:${resource.name}`;
196
+ }
package/CHANGELOG.md DELETED
@@ -1,206 +0,0 @@
1
- # Changelog
2
-
3
- ## 1.8.2
4
-
5
- ### Patch Changes
6
-
7
- - 23056c6: update packages, fix lint errors
8
-
9
- ## 1.8.1
10
-
11
- ### Patch Changes
12
-
13
- - 995cf22: fix \_\_dirname not defined
14
-
15
- ## 1.8.0
16
-
17
- ### Minor Changes
18
-
19
- - 5145047: - node 20 is minimal engine now
20
- - sort exports according to package type so `require` is higher than `import` for type === "module" and lower for type === "commonjs"
21
- - wait for tsconfig being processed before processing the package
22
- - do not write declarations if they are not enabled in tsconfig
23
- - remove 'packageManager' from package.json on prune
24
- - consume jsconfig.json
25
- - do not write exports option
26
- - handle directories.bin in package.json
27
- - use es modules where possible
28
-
29
- ## 1.7.3
30
-
31
- ### Patch Changes
32
-
33
- - 0091f32: added support for typesVersions
34
-
35
- ## 1.7.2
36
-
37
- ### Patch Changes
38
-
39
- - d942874: use prune
40
-
41
- ## 1.7.1
42
-
43
- ### Patch Changes
44
-
45
- - added prepack to self
46
-
47
- ## 1.7.0
48
-
49
- ### Minor Changes
50
-
51
- - 633fa9f: fixed command line parameters update
52
- added simplified status per option in main menu
53
-
54
- ## 1.6.0
55
-
56
- ### Minor Changes
57
-
58
- - 0438287: use shared internal library to parse options / package.json
59
-
60
- ## 1.5.0
61
-
62
- ### Minor Changes
63
-
64
- - fdcf99f: extended include-externals to specify individual externals
65
-
66
- ## 1.4.6
67
-
68
- ### Patch Changes
69
-
70
- - 9ce9955: added non-standart unpkg to package fields list
71
-
72
- ## 1.4.5
73
-
74
- ### Patch Changes
75
-
76
- - cc06bb8: make quiet really quiet
77
- - 5f6883e: add newline to package.json same way as pkgbld does
78
- - b203bae: stricter package.json parsing
79
-
80
- ## 1.4.4
81
-
82
- ### Patch Changes
83
-
84
- - 5950c96: added more fields for ordering
85
-
86
- ## 1.4.3
87
-
88
- ### Patch Changes
89
-
90
- - 5fac6a1: fix: handle author object
91
-
92
- ## 1.4.2
93
-
94
- ### Patch Changes
95
-
96
- - 54ce107: fix typo
97
-
98
- ## 1.4.1
99
-
100
- ### Patch Changes
101
-
102
- - ea0a7cb: remove redundunt debug console.log()
103
- - 1e0d5a4: update packages to match new structure
104
- - fd406cc: added missing `readme` field
105
-
106
- ## 1.4.0
107
-
108
- ### Minor Changes
109
-
110
- - 1cf3eb4: more advanced implementation to allow create / update more complex packages (still some features missing)
111
-
112
- ## 1.3.0
113
-
114
- ### Minor Changes
115
-
116
- - 3daff62: Added a menu to quickly edit package
117
-
118
- ## 1.2.0
119
-
120
- ### Minor Changes
121
-
122
- - b4556f5: simplified package so it provides bare minimum of functionality, fixed issue running in current / another directory, added automatic directory creation
123
-
124
- ## 1.1.10
125
-
126
- ### Patch Changes
127
-
128
- - 86c8d88: updated processing logic of default, module and types fields in package.json
129
-
130
- ## 1.1.9
131
-
132
- ### Patch Changes
133
-
134
- - 74a7f67: fix small mistakes in documentation
135
-
136
- ## 1.1.8
137
-
138
- ### Patch Changes
139
-
140
- - 1e29b8e: Fixed path to executable file in package.json
141
-
142
- ## 1.1.7
143
-
144
- ### Patch Changes
145
-
146
- - fc6c99a: Updated documentation and links
147
-
148
- ## 1.1.6
149
-
150
- ### Patch Changes
151
-
152
- - 03f2a71: Updated dependencies
153
-
154
- ## 1.1.5
155
-
156
- ### Patch Changes
157
-
158
- - 85c2ae6: When creating subpackage, assume that subpackage should be created in subdirectory if package name (cli argument) is not provided
159
-
160
- ## [1.1.4](https://github.com/kshutkin/create-pkgbld/compare/v1.1.3...v1.1.4) (2022-11-01)
161
-
162
- ### Bug Fixes
163
-
164
- - upgrade minimist from 1.2.6 to 1.2.7 ([#3](https://github.com/kshutkin/create-pkgbld/issues/3)) ([c24c8e3](https://github.com/kshutkin/create-pkgbld/commit/c24c8e3a838d409f980acf90142676312b207860))
165
-
166
- ## [1.1.3](https://github.com/kshutkin/create-pkgbld/compare/v1.1.2...v1.1.3) (2022-03-23)
167
-
168
- ### Bug Fixes
169
-
170
- - readme link ([6009ea8](https://github.com/kshutkin/create-pkgbld/commit/6009ea82fe06af9d939c5dd4747f08a94955b3d4))
171
-
172
- ## [1.1.2](https://github.com/kshutkin/create-pkgbld/compare/v1.1.1...v1.1.2) (2022-03-23)
173
-
174
- ### Bug Fixes
175
-
176
- - package.json & package-lock.json to reduce vulnerabilities ([#2](https://github.com/kshutkin/create-pkgbld/issues/2)) ([5d72496](https://github.com/kshutkin/create-pkgbld/commit/5d724967f1e1a4b33d24d197b99e15a7a244e301))
177
-
178
- ## [1.1.1](https://github.com/kshutkin/create-pkgbld/compare/v1.1.0...v1.1.1) (2022-02-13)
179
-
180
- ### Bug Fixes
181
-
182
- - use dirname ([6a5d8bb](https://github.com/kshutkin/create-pkgbld/commit/6a5d8bb23580f1639671e92b922b6df744299dc9))
183
-
184
- # [1.1.0](https://github.com/kshutkin/create-pkgbld/compare/v1.0.2...v1.1.0) (2022-02-13)
185
-
186
- ### Features
187
-
188
- - display version on start ([c7c7051](https://github.com/kshutkin/create-pkgbld/commit/c7c7051bf4e4fe5f037891505de2addddf3b69ac))
189
-
190
- ## [1.0.2](https://github.com/kshutkin/create-pkgbld/compare/v1.0.1...v1.0.2) (2022-02-08)
191
-
192
- ### Bug Fixes
193
-
194
- - do not cache ([ced7de5](https://github.com/kshutkin/create-pkgbld/commit/ced7de5f3e092c4a91afb92368364387725738c9))
195
-
196
- ## [1.0.1](https://github.com/kshutkin/create-pkgbld/compare/v1.0.0...v1.0.1) (2021-12-28)
197
-
198
- ### Bug Fixes
199
-
200
- - undefined exception when run without arguments ([179e44a](https://github.com/kshutkin/create-pkgbld/commit/179e44a87fdfedb46b49053b2d7e245825188003))
201
-
202
- # 1.0.0 (2021-12-27)
203
-
204
- ### Features
205
-
206
- - initial implementation ([#1](https://github.com/kshutkin/create-pkgbld/issues/1)) ([1fa648a](https://github.com/kshutkin/create-pkgbld/commit/1fa648ad2a06ffbb9116efb3501c68cd40de40ce))
package/eslint.config.mjs DELETED
@@ -1,42 +0,0 @@
1
- import typescriptEslint from '@typescript-eslint/eslint-plugin';
2
- import globals from 'globals';
3
- import tsParser from '@typescript-eslint/parser';
4
- import path from 'node:path';
5
- import { fileURLToPath } from 'node:url';
6
- import js from '@eslint/js';
7
- import { FlatCompat } from '@eslint/eslintrc';
8
-
9
- const __filename = fileURLToPath(import.meta.url);
10
- const __dirname = path.dirname(__filename);
11
- const compat = new FlatCompat({
12
- baseDirectory: __dirname,
13
- recommendedConfig: js.configs.recommended,
14
- allConfig: js.configs.all
15
- });
16
-
17
- export default [
18
- ...compat.extends('eslint:recommended', 'plugin:@typescript-eslint/recommended'),
19
- {
20
- plugins: {
21
- '@typescript-eslint': typescriptEslint,
22
- },
23
-
24
- languageOptions: {
25
- globals: {
26
- ...globals.browser,
27
- },
28
-
29
- parser: tsParser,
30
- ecmaVersion: 13,
31
- sourceType: 'module',
32
- },
33
-
34
- rules: {
35
- '@typescript-eslint/no-non-null-assertion': ['off'],
36
- indent: ['error', 4],
37
- 'linebreak-style': ['error', 'unix'],
38
- quotes: ['error', 'single'],
39
- semi: ['error', 'always'],
40
- },
41
- },
42
- ];