@git.zone/tspublish 1.11.6 → 1.12.1

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.
@@ -2,7 +2,7 @@ import * as plugins from './plugins.js';
2
2
  import * as paths from './paths.js';
3
3
  import { logger, logInfo, logSuccess, logWarn, logError, logBuild, logPublish, logOngoing, logStart, logDone } from './logging.js';
4
4
 
5
- import { type ITsPublishJson } from './interfaces/index.js';
5
+ import { type ITsPublishJson, type ITsPublishModulePlan } from './interfaces/index.js';
6
6
  import type { TsPublish } from './classes.tspublish.js';
7
7
 
8
8
  export interface IPublishModuleOptions {
@@ -14,6 +14,7 @@ export interface IPublishModuleOptions {
14
14
  name?: string;
15
15
  version?: string;
16
16
  dependencies?: { [key: string]: string };
17
+ modulePlan?: ITsPublishModulePlan;
17
18
  }
18
19
 
19
20
  export interface IResolvedRegistry {
@@ -48,20 +49,10 @@ export class PublishModule {
48
49
  const packageJsonContent = await plugins.smartfs.file(packageJsonPath).encoding('utf8').read();
49
50
  const monoRepoPackageJson = JSON.parse(packageJsonContent as string);
50
51
 
51
- this.options.dependencies = {
52
- ...this.options.dependencies,
53
- ...(() => {
54
- const resultDependencies: Record<string, string> = {};
55
- for (const dependency of this.options.tsPublishJson!.dependencies) {
56
- if (monoRepoPackageJson.dependencies[dependency]) {
57
- resultDependencies[dependency] = monoRepoPackageJson.dependencies[dependency];
58
- } else {
59
- resultDependencies[dependency] = monoRepoPackageJson.version;
60
- }
61
- }
62
- return resultDependencies;
63
- })(),
64
- };
52
+ this.options.modulePlan ??= (await this.tsPublishRef.plan(this.options.monoRepoDir)).modules
53
+ .find((module) => module.folder === this.options.packageSubFolder);
54
+ if (!this.options.modulePlan) throw new Error('Missing publish module plan.');
55
+ this.options.dependencies = this.options.modulePlan.manifest.dependencies;
65
56
  this.options.name = this.options.name || this.options.tsPublishJson!.name;
66
57
  this.options.version = monoRepoPackageJson.version;
67
58
 
@@ -81,7 +72,7 @@ export class PublishModule {
81
72
  logError(
82
73
  `Package ${this.options.name} already exists with version ${this.options.version}`
83
74
  );
84
- process.exit(1);
75
+ throw new Error(`Package ${this.options.name} already exists with version ${this.options.version}.`);
85
76
  }
86
77
  }
87
78
  }
@@ -126,44 +117,18 @@ export class PublishModule {
126
117
  }
127
118
 
128
119
  public async createPackageJson() {
120
+ if (!this.options.modulePlan) throw new Error('Publish module must be initialized first.');
121
+ const rootManifest = JSON.parse(await plugins.fs.readFile(plugins.path.join(this.options.monoRepoDir, 'package.json'), 'utf8'));
122
+ const buildVersion = rootManifest.devDependencies?.['@git.zone/tsbuild'] ?? rootManifest.dependencies?.['@git.zone/tsbuild'];
123
+ if (typeof buildVersion !== 'string' || !buildVersion) throw new Error('Publishing requires a declared @git.zone/tsbuild version.');
129
124
  const packageJson = {
130
- name: this.options.name,
131
- version: this.options.version,
132
- type: 'module',
133
- description: '',
134
- exports: {
135
- '.': {
136
- import: `./dist_${this.options.packageSubFolder}/index.js`,
137
- },
138
- },
125
+ ...this.options.modulePlan.manifest,
139
126
  scripts: {
140
127
  build: 'tsbuild tsfolders',
141
128
  },
142
- dependencies: this.options.dependencies,
143
129
  devDependencies: {
144
- '@git.zone/tsbuild': await this.getLatestVersionOfPackage('@git.zone/tsbuild'),
130
+ '@git.zone/tsbuild': buildVersion,
145
131
  },
146
- files: [
147
- 'ts/**/*',
148
- 'ts_*/**/*',
149
- 'dist/**/*',
150
- 'dist_*/**/*',
151
- 'dist_ts/**/*',
152
- 'dist_ts_web/**/*',
153
- 'assets/**/*',
154
- 'cli.js',
155
- '.smartconfig.json',
156
- 'readme.md',
157
- ],
158
- ...this.options.tsPublishJson?.bin ? {
159
- bin: (() => {
160
- const binObject: {[key: string]: string} = {};
161
- for (const bin of this.options.tsPublishJson!.bin) {
162
- binObject[bin] = `./cli.js`;
163
- }
164
- return binObject;
165
- })()
166
- } : {},
167
132
  };
168
133
  return JSON.stringify(packageJson, null, 2);
169
134
  }
@@ -191,8 +156,13 @@ export class PublishModule {
191
156
  await plugins.smartfs.file(tsconfigJsonPath).encoding('utf8').write(await this.createTsconfigJson());
192
157
 
193
158
  // ts subfolder, the folder that contains the source code and is being transpiled
194
- const destSubFolder = plugins.path.join(this.options.publishModDirFullPath, this.options.packageSubFolder);
195
- await plugins.smartfs.directory(this.options.packageSubFolderFullPath!).recursive().copy(destSubFolder);
159
+ for (const folder of this.options.modulePlan!.folders) {
160
+ await plugins.smartfs.directory(plugins.path.join(this.options.monoRepoDir, folder)).recursive()
161
+ .copy(plugins.path.join(this.options.publishModDirFullPath, folder));
162
+ }
163
+ for (const path of this.options.modulePlan!.include) {
164
+ await plugins.fs.cp(plugins.path.join(this.options.monoRepoDir, path), plugins.path.join(this.options.publishModDirFullPath, path), { recursive: true });
165
+ }
196
166
 
197
167
  // readme
198
168
  const readmeSrc = plugins.path.join(this.options.packageSubFolderFullPath!, 'readme.md');
@@ -200,12 +170,12 @@ export class PublishModule {
200
170
  await plugins.smartfs.file(readmeSrc).copy(readmeDest);
201
171
 
202
172
  // license
203
- const licenseSrc = plugins.path.join(this.options.monoRepoDir, 'license');
204
- const licenseDest = plugins.path.join(this.options.publishModDirFullPath, 'license');
173
+ const licenseSrc = plugins.path.join(this.options.monoRepoDir, this.options.modulePlan!.licenseFile);
174
+ const licenseDest = plugins.path.join(this.options.publishModDirFullPath, this.options.modulePlan!.licenseFile);
205
175
  await plugins.smartfs.file(licenseSrc).copy(licenseDest);
206
176
 
207
177
  // cli stuff
208
- this.createBinCliSetup();
178
+ await this.createBinCliSetup();
209
179
  }
210
180
 
211
181
  public async build() {
@@ -222,13 +192,9 @@ export class PublishModule {
222
192
  !!this.options.tsPublishJson?.bin &&
223
193
  Array.isArray(this.options.tsPublishJson!.bin) &&
224
194
  this.options.tsPublishJson!.bin.length > 0;
225
- const files = await this.tsPublishRef.giteaAssetsInstance.getFiles(
226
- 'git.zone',
227
- 'cli',
228
- 'assets/templates/cli/cli.js'
229
- );
195
+ if (!binSetupApplies) return;
230
196
  const indexPath = `./dist_${this.options.packageSubFolder}/index.js`;
231
- const fileContent = atob(files[0].base64Content!).replace('./dist_ts/index.js', indexPath);
197
+ const fileContent = `#!/usr/bin/env node\nprocess.env.CLI_CALL = 'true';\nconst cliTool = await import(${JSON.stringify(indexPath)});\nawait cliTool.runCli();\n`;
232
198
  const cliJsPath = plugins.path.join(this.options.publishModDirFullPath!, 'cli.js');
233
199
  await plugins.smartfs.file(cliJsPath).encoding('utf8').write(fileContent);
234
200
  }
@@ -258,8 +224,8 @@ export class PublishModule {
258
224
  if (hasUseBase || hasExtendBase) {
259
225
  const smartconfigInstance = new plugins.smartconfig.Smartconfig(this.options.monoRepoDir);
260
226
  const gitzoneConfig = smartconfigInstance.dataFor<any>('@git.zone/cli', {});
261
- baseRegistries = gitzoneConfig?.release?.registries || [];
262
- baseAccessLevel = gitzoneConfig?.release?.accessLevel || 'public';
227
+ baseRegistries = gitzoneConfig?.release?.targets?.npm?.registries ?? gitzoneConfig?.release?.registries ?? [];
228
+ baseAccessLevel = gitzoneConfig?.release?.targets?.npm?.accessLevel ?? gitzoneConfig?.release?.accessLevel ?? 'public';
263
229
 
264
230
  if (baseRegistries.length === 0) {
265
231
  throw new Error(
@@ -4,6 +4,8 @@ import * as interfaces from './interfaces/index.js';
4
4
 
5
5
  import { PublishModule } from './classes.publishmodule.js';
6
6
  import { GiteaAssets } from './classes.giteaassets.js';
7
+ import { createPackagePlan, orderPublishModules } from './functions.packageplan.js';
8
+ import { PackagePreparer } from './classes.packagepreparer.js';
7
9
 
8
10
  export class TsPublish {
9
11
  public giteaAssetsInstance: GiteaAssets;
@@ -17,6 +19,7 @@ export class TsPublish {
17
19
  public async publish(monorepoDirArg: string) {
18
20
  logHeader('TSPublish - Module Publisher');
19
21
  const publishModules = await this.getModuleSubDirs(monorepoDirArg);
22
+ const plan = await createPackagePlan(monorepoDirArg, publishModules);
20
23
  logInfo(`Found ${Object.keys(publishModules).length} publish modules`);
21
24
  logSeparator();
22
25
  for (const publishModule of Object.keys(publishModules)) {
@@ -31,6 +34,7 @@ export class TsPublish {
31
34
  const publishModuleInstance = new PublishModule(this, {
32
35
  monoRepoDir: monorepoDirArg,
33
36
  packageSubFolder: publishModule,
37
+ modulePlan: plan.modules.find((module) => module.folder === publishModule),
34
38
  });
35
39
  const moduleCount = Object.keys(publishModules).indexOf(publishModule) + 1;
36
40
  const totalCount = Object.keys(publishModules).length;
@@ -42,6 +46,17 @@ export class TsPublish {
42
46
  }
43
47
  }
44
48
 
49
+ /** Read-only package discovery, dependency ordering and manifest validation. */
50
+ public async plan(directory: string): Promise<interfaces.ITsPublishPlan> {
51
+ return createPackagePlan(directory, await this.getModuleSubDirs(directory));
52
+ }
53
+
54
+ /** Prepare built modules for a release owner; never publishes or contacts a registry. */
55
+ public async prepare(directory: string, outputDirectory: string): Promise<interfaces.ITsPublishPreparedModule[]> {
56
+ const plan = await this.plan(directory);
57
+ return new PackagePreparer(directory).prepare(plan, outputDirectory);
58
+ }
59
+
45
60
  public async getModuleSubDirs(dirArg: string) {
46
61
  // List all directories
47
62
  const dirContents = await plugins.smartfs.directory(dirArg).list();
@@ -68,6 +83,6 @@ export class TsPublish {
68
83
  logSuccess(`Found ${Object.keys(publishModules).length} publish modules`);
69
84
  logInfo('Ordering publish modules...');
70
85
 
71
- return publishModules;
86
+ return orderPublishModules(publishModules);
72
87
  }
73
88
  }
@@ -0,0 +1,182 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { ITsPublishJson, ITsPublishManifest, ITsPublishPlan, TTsPublishExport } from './interfaces/index.js';
3
+
4
+ const packageNamePattern = /^(?:@[a-z0-9][a-z0-9._-]*\/)?[a-z0-9][a-z0-9._-]*$/;
5
+ const folderPattern = /^ts(?:_[a-z0-9_]+)?$/;
6
+
7
+ export const assertPackagePath = (value: string): void => {
8
+ if (typeof value !== 'string' || !value || value.includes('\\')
9
+ || value.split('/').some((part) => !part || part === '.' || part === '..')
10
+ || /[\x00-\x1f\x7f*?]/.test(value) || plugins.path.isAbsolute(value)) {
11
+ throw new Error(`Invalid package-relative path: ${value}`);
12
+ }
13
+ };
14
+
15
+ const record = (value: unknown, label: string): Record<string, unknown> => {
16
+ if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error(`Invalid ${label}.`);
17
+ return value as Record<string, unknown>;
18
+ };
19
+
20
+ const dependencyNames = (value: unknown, label: string): string[] => {
21
+ if (!Array.isArray(value) || value.some((name) => typeof name !== 'string' || !packageNamePattern.test(name))
22
+ || new Set(value).size !== value.length) throw new Error(`Invalid ${label}.`);
23
+ return value;
24
+ };
25
+
26
+ const assertVersionReference = (value: unknown, name: string): string => {
27
+ if (typeof value !== 'string' || !value.trim() || /^(?:file|link|workspace):/.test(value)) {
28
+ throw new Error(`Missing or unsupported published dependency version for ${name}.`);
29
+ }
30
+ return value;
31
+ };
32
+
33
+ const stringRecord = (value: unknown, label: string): Record<string, string> => {
34
+ const result = record(value, label);
35
+ if (Object.values(result).some((entry) => typeof entry !== 'string' || !entry.trim())) throw new Error(`Invalid ${label}.`);
36
+ return result as Record<string, string>;
37
+ };
38
+
39
+ const legacyEntry = (value: TTsPublishExport, kind: 'main' | 'types'): string | undefined => {
40
+ if (typeof value === 'string') return kind === 'main' ? value : undefined;
41
+ if (value === null) return undefined;
42
+ if (kind === 'types' && typeof value.types === 'string') return value.types;
43
+ for (const condition of ['node', 'import', 'default']) {
44
+ if (value[condition] !== undefined) {
45
+ const result = legacyEntry(value[condition], kind);
46
+ if (result) return result;
47
+ }
48
+ }
49
+ return undefined;
50
+ };
51
+
52
+ export const orderPublishModules = (
53
+ modules: Record<string, ITsPublishJson>,
54
+ ): Record<string, ITsPublishJson> => {
55
+ const names = new Map<string, string>();
56
+ for (const [folder, config] of Object.entries(modules)) {
57
+ if (config.order !== undefined && !Number.isFinite(config.order)) throw new Error(`Invalid order for ${folder}.`);
58
+ if (config.name) {
59
+ if (!packageNamePattern.test(config.name) || names.has(config.name)) throw new Error(`Invalid or duplicate package name: ${config.name}`);
60
+ names.set(config.name, folder);
61
+ }
62
+ }
63
+ const pending = new Set(Object.keys(modules));
64
+ const ordered: Record<string, ITsPublishJson> = {};
65
+ while (pending.size) {
66
+ const ready = [...pending].filter((folder) =>
67
+ [...(modules[folder].dependencies ?? []), ...(modules[folder].optionalDependencies ?? [])]
68
+ .every((name) => !names.has(name) || !pending.has(names.get(name)!)),
69
+ ).sort((a, b) => (modules[a].order ?? Number.MAX_SAFE_INTEGER) - (modules[b].order ?? Number.MAX_SAFE_INTEGER)
70
+ || a.localeCompare(b, 'en'));
71
+ if (!ready.length) throw new Error(`Cyclic publish dependencies: ${[...pending].join(', ')}`);
72
+ const folder = ready[0];
73
+ ordered[folder] = modules[folder];
74
+ pending.delete(folder);
75
+ }
76
+ return ordered;
77
+ };
78
+
79
+ const validateExport = (value: TTsPublishExport, folders: string[]): void => {
80
+ if (value === null) return;
81
+ if (typeof value === 'string') {
82
+ if (!value.startsWith('./')) throw new Error('Package export targets must be relative.');
83
+ assertPackagePath(value.slice(2));
84
+ if (!folders.some((folder) => value.startsWith(`./dist_${folder}/`))) {
85
+ throw new Error(`Export target is outside this package's compiled folders: ${value}`);
86
+ }
87
+ return;
88
+ }
89
+ for (const child of Object.values(record(value, 'export conditions'))) validateExport(child as TTsPublishExport, folders);
90
+ };
91
+
92
+ export const createPackagePlan = async (
93
+ directory: string,
94
+ discovered: Record<string, ITsPublishJson>,
95
+ ): Promise<ITsPublishPlan> => {
96
+ const root = record(JSON.parse(await plugins.fs.readFile(plugins.path.join(directory, 'package.json'), 'utf8')), 'root manifest');
97
+ if (typeof root.version !== 'string' || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?(?:\+[0-9A-Za-z.-]+)?$/.test(root.version)) {
98
+ throw new Error('The repository requires a concrete package version.');
99
+ }
100
+ const ordered = orderPublishModules(discovered);
101
+ const names = new Set(Object.values(ordered).map((config) => config.name).filter(Boolean));
102
+ const owners = new Set<string>();
103
+ const rootDependencies = record(root.dependencies ?? {}, 'root dependencies');
104
+ const version = root.version;
105
+ let licenseFile = 'license.md';
106
+ try { await plugins.fs.access(plugins.path.join(directory, licenseFile)); }
107
+ catch (error) {
108
+ if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
109
+ licenseFile = 'license';
110
+ await plugins.fs.access(plugins.path.join(directory, licenseFile));
111
+ }
112
+ const modules: ITsPublishPlan['modules'] = [];
113
+ for (const [folder, config] of Object.entries(ordered)) {
114
+ if (!config.name) continue; // tsbuild also consumes order-only descriptors.
115
+ const folders = [folder, ...(config.folders ?? [])];
116
+ if (folders.some((name) => !folderPattern.test(name) || owners.has(name)) || new Set(folders).size !== folders.length) {
117
+ throw new Error(`Invalid or multiply owned source folder for ${config.name}.`);
118
+ }
119
+ folders.forEach((name) => owners.add(name));
120
+ const resolveDependencies = (value: unknown, label: string): Record<string, string> => Object.fromEntries(
121
+ dependencyNames(value, label).map((name) => [name, names.has(name)
122
+ ? version : assertVersionReference(rootDependencies[name], name)]),
123
+ );
124
+ const dependencies = resolveDependencies(config.dependencies ?? [], `${config.name} dependencies`);
125
+ const optionalDependencies = config.optionalDependencies
126
+ ? resolveDependencies(config.optionalDependencies, `${config.name} optional dependencies`) : undefined;
127
+ for (const [name, range] of Object.entries(stringRecord(config.peerDependencies ?? {}, 'peer dependencies'))) {
128
+ if (!packageNamePattern.test(name)) throw new Error(`Invalid peer dependency: ${name}`);
129
+ assertVersionReference(range, name);
130
+ }
131
+ for (const [name, metadataValue] of Object.entries(record(config.peerDependenciesMeta ?? {}, 'peer metadata'))) {
132
+ const metadata = record(metadataValue, 'peer metadata');
133
+ if (!(name in (config.peerDependencies ?? {})) || Object.keys(record(metadata, 'peer metadata')).some((key) => key !== 'optional')
134
+ || (metadata.optional !== undefined && typeof metadata.optional !== 'boolean')) throw new Error(`Invalid peer metadata for ${name}.`);
135
+ }
136
+ const exports = record(config.exports ?? { '.': { types: `./dist_${folder}/index.d.ts`, import: `./dist_${folder}/index.js` } }, 'package exports') as Record<string, TTsPublishExport>;
137
+ for (const [key, target] of Object.entries(exports)) {
138
+ if (key !== '.' && !key.startsWith('./')) throw new Error(`Invalid package export: ${key}`);
139
+ if (key !== '.') assertPackagePath(key.slice(2));
140
+ validateExport(target, folders);
141
+ }
142
+ if (!exports['.']) throw new Error(`${config.name} requires a root export.`);
143
+ const include = config.include ?? [];
144
+ if (!Array.isArray(include) || new Set(include).size !== include.length) throw new Error('Invalid package include paths.');
145
+ include.forEach(assertPackagePath);
146
+ if (include.some((path) => ['package.json', 'readme.md', 'cli.js', 'node_modules', '.git'].includes(path.split('/')[0])
147
+ || folderPattern.test(path.split('/')[0]) || /^dist_ts(?:_[a-z0-9_]+)?$/.test(path.split('/')[0])
148
+ || folders.some((folder) => path === folder || path.startsWith(`${folder}/`) || path === `dist_${folder}` || path.startsWith(`dist_${folder}/`)))) {
149
+ throw new Error('Explicit includes cannot replace generated package files or source folders.');
150
+ }
151
+ const bin = config.bin ?? [];
152
+ if (!Array.isArray(bin) || bin.some((name) => typeof name !== 'string' || !/^[a-z0-9][a-z0-9._-]*$/.test(name))) throw new Error('Invalid package binaries.');
153
+ const metadata = Object.fromEntries(['author', 'license', 'repository', 'homepage', 'bugs', 'keywords', 'funding'].filter((key) => root[key] !== undefined).map((key) => [key, root[key]]));
154
+ const description = config.description ?? root.description ?? '';
155
+ if (typeof description !== 'string') throw new Error('Invalid package description.');
156
+ const engines = config.engines ?? root.engines;
157
+ if (engines !== undefined) stringRecord(engines, 'package engines');
158
+ if (config.sideEffects !== undefined && typeof config.sideEffects !== 'boolean'
159
+ && (!Array.isArray(config.sideEffects) || config.sideEffects.some((value) => typeof value !== 'string' || !value.trim()))) {
160
+ throw new Error('Invalid sideEffects metadata.');
161
+ }
162
+ const main = legacyEntry(exports['.'], 'main');
163
+ const types = legacyEntry(exports['.'], 'types');
164
+ const manifest: ITsPublishManifest = {
165
+ ...metadata, name: config.name, version, type: 'module', description,
166
+ ...(main ? { main } : {}), ...(types ? { types } : {}), exports, dependencies,
167
+ ...(optionalDependencies ? { optionalDependencies } : {}),
168
+ ...(config.peerDependencies ? { peerDependencies: config.peerDependencies } : {}),
169
+ ...(config.peerDependenciesMeta ? { peerDependenciesMeta: config.peerDependenciesMeta } : {}),
170
+ ...(engines !== undefined ? { engines: engines as Record<string, string> } : {}),
171
+ ...(config.sideEffects !== undefined ? { sideEffects: config.sideEffects } : {}),
172
+ ...(bin.length ? { bin: Object.fromEntries(bin.map((name) => [name, './cli.js'])) } : {}),
173
+ files: [...folders.flatMap((name) => [name, `dist_${name}`]), ...include, 'readme.md', licenseFile, ...(bin.length ? ['cli.js'] : [])],
174
+ };
175
+ if (config.registries !== undefined && (!Array.isArray(config.registries) || config.registries.some((registry) => typeof registry !== 'string' || !registry.trim() || registry !== registry.trim() || /[\x00-\x1f\x7f]/.test(registry)))) {
176
+ throw new Error(`Invalid registry declarations for ${config.name}.`);
177
+ }
178
+ modules.push({ folder, folders, name: config.name, version, order: modules.length, manifest, include, licenseFile, registries: config.registries ?? [] });
179
+ }
180
+ if (!modules.length) throw new Error('No named tspublish modules were found.');
181
+ return { schemaVersion: 1, version, modules };
182
+ };
package/ts/index.ts CHANGED
@@ -3,9 +3,19 @@ import { TsPublish } from './classes.tspublish.js';
3
3
  import { logStart } from './logging.js';
4
4
 
5
5
  export * from './classes.tspublish.js';
6
+ export type * from './interfaces/index.js';
6
7
 
7
8
  export const runCli = async () => {
8
9
  logStart('tspublish');
9
10
  const tspublish = new TsPublish();
10
- await tspublish.publish(paths.cwd);
11
+ const args = process.argv.slice(2);
12
+ if (args[0] === 'plan' && args.length === 1) {
13
+ console.log(JSON.stringify(await tspublish.plan(paths.cwd), null, 2));
14
+ } else if (args[0] === 'prepare' && args.length === 2) {
15
+ console.log(JSON.stringify(await tspublish.prepare(paths.cwd, args[1]), null, 2));
16
+ } else if (args.length === 0) {
17
+ await tspublish.publish(paths.cwd);
18
+ } else {
19
+ throw new Error('Usage: tspublish [plan | prepare <new-output-directory>]');
20
+ }
11
21
  };
@@ -10,4 +10,59 @@ export interface ITsPublishJson {
10
10
  * allows the sepcification of bin names that invoke cli scripts
11
11
  */
12
12
  bin: string[];
13
+ description?: string;
14
+ /** Additional source folders owned by this package, for example subpath exports. */
15
+ folders?: string[];
16
+ exports?: Record<string, TTsPublishExport>;
17
+ peerDependencies?: Record<string, string>;
18
+ peerDependenciesMeta?: Record<string, { optional?: boolean }>;
19
+ optionalDependencies?: string[];
20
+ engines?: Record<string, string>;
21
+ sideEffects?: boolean | string[];
22
+ /** Explicit repository-relative asset files/directories to include unchanged. */
23
+ include?: string[];
24
+ }
25
+
26
+ export type TTsPublishExport = string | null | { [condition: string]: TTsPublishExport };
27
+
28
+ export interface ITsPublishManifest {
29
+ name: string;
30
+ version: string;
31
+ type: 'module';
32
+ description: string;
33
+ main?: string;
34
+ types?: string;
35
+ exports: Record<string, TTsPublishExport>;
36
+ dependencies: Record<string, string>;
37
+ optionalDependencies?: Record<string, string>;
38
+ peerDependencies?: Record<string, string>;
39
+ peerDependenciesMeta?: Record<string, { optional?: boolean }>;
40
+ engines?: Record<string, string>;
41
+ sideEffects?: boolean | string[];
42
+ bin?: Record<string, string>;
43
+ files: string[];
44
+ [key: string]: unknown;
45
+ }
46
+
47
+ export interface ITsPublishModulePlan {
48
+ folder: string;
49
+ folders: string[];
50
+ name: string;
51
+ version: string;
52
+ /** Position in the deterministic dependency order. */
53
+ order: number;
54
+ manifest: ITsPublishManifest;
55
+ include: string[];
56
+ licenseFile: string;
57
+ registries: string[];
58
+ }
59
+
60
+ export interface ITsPublishPlan {
61
+ schemaVersion: 1;
62
+ version: string;
63
+ modules: ITsPublishModulePlan[];
64
+ }
65
+
66
+ export interface ITsPublishPreparedModule extends ITsPublishModulePlan {
67
+ directory: string;
13
68
  }
package/ts/plugins.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  // node native scope
2
- import * as path from 'path';
3
- export { path };
2
+ import * as path from 'node:path';
3
+ import * as fs from 'node:fs/promises';
4
+ import { isBuiltin } from 'node:module';
5
+ import * as typescript from 'typescript';
6
+ export { path, fs, isBuiltin, typescript };
4
7
 
5
8
  // @push.rocks scope
6
9
  import * as consolecolor from '@push.rocks/consolecolor';
File without changes