@pgpmjs/core 7.0.0 → 7.2.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/bundle/apply.d.ts +93 -0
- package/bundle/apply.js +137 -0
- package/bundle/index.d.ts +12 -0
- package/bundle/index.js +31 -0
- package/core/class/pgpm.d.ts +2 -2
- package/core/class/pgpm.js +6 -6
- package/esm/bundle/apply.js +131 -0
- package/esm/bundle/index.js +15 -0
- package/esm/core/class/pgpm.js +6 -6
- package/esm/index.js +7 -3
- package/esm/migrate/client.js +1 -1
- package/esm/migrate/utils/hash.js +3 -6
- package/esm/modules/modules.js +1 -1
- package/esm/packaging/package.js +40 -24
- package/esm/rebundle/index.js +4 -0
- package/esm/rebundle/module.js +111 -0
- package/esm/rebundle/rebundle.js +170 -0
- package/esm/rebundle/workspace.js +170 -0
- package/esm/refactor/rename.js +5 -27
- package/esm/resolution/deps.js +2 -2
- package/esm/resolution/resolve.js +2 -2
- package/esm/slice/slice.js +1 -1
- package/esm/workspace/minimal.js +73 -0
- package/index.d.ts +6 -2
- package/index.js +8 -4
- package/migrate/client.js +1 -1
- package/migrate/utils/hash.d.ts +2 -4
- package/migrate/utils/hash.js +4 -8
- package/modules/modules.d.ts +1 -1
- package/modules/modules.js +1 -1
- package/package.json +4 -2
- package/packaging/package.d.ts +23 -1
- package/packaging/package.js +42 -25
- package/rebundle/index.d.ts +4 -0
- package/{files/sql-scripts → rebundle}/index.js +4 -2
- package/rebundle/module.d.ts +23 -0
- package/rebundle/module.js +116 -0
- package/rebundle/rebundle.d.ts +26 -0
- package/rebundle/rebundle.js +175 -0
- package/rebundle/types.d.ts +185 -0
- package/rebundle/workspace.d.ts +15 -0
- package/rebundle/workspace.js +173 -0
- package/refactor/rename.d.ts +2 -8
- package/refactor/rename.js +6 -29
- package/resolution/deps.d.ts +1 -1
- package/resolution/deps.js +2 -2
- package/resolution/resolve.js +2 -2
- package/slice/slice.d.ts +1 -1
- package/slice/slice.js +1 -1
- package/slice/types.d.ts +1 -1
- package/workspace/minimal.d.ts +64 -0
- package/workspace/minimal.js +82 -0
- package/esm/files/extension/index.js +0 -3
- package/esm/files/extension/reader.js +0 -79
- package/esm/files/extension/writer.js +0 -99
- package/esm/files/index.js +0 -6
- package/esm/files/plan/generator.js +0 -82
- package/esm/files/plan/index.js +0 -5
- package/esm/files/plan/parser.js +0 -297
- package/esm/files/plan/validators.js +0 -181
- package/esm/files/plan/writer.js +0 -142
- package/esm/files/sql/header.js +0 -259
- package/esm/files/sql/index.js +0 -2
- package/esm/files/sql/writer.js +0 -107
- package/esm/files/sql-scripts/index.js +0 -2
- package/esm/files/sql-scripts/reader.js +0 -19
- package/esm/files/types/index.js +0 -1
- package/esm/utils/author.js +0 -11
- package/files/extension/index.d.ts +0 -2
- package/files/extension/index.js +0 -19
- package/files/extension/reader.d.ts +0 -24
- package/files/extension/reader.js +0 -86
- package/files/extension/writer.d.ts +0 -48
- package/files/extension/writer.js +0 -107
- package/files/index.d.ts +0 -5
- package/files/index.js +0 -22
- package/files/plan/generator.d.ts +0 -23
- package/files/plan/generator.js +0 -90
- package/files/plan/index.d.ts +0 -4
- package/files/plan/index.js +0 -21
- package/files/plan/parser.d.ts +0 -28
- package/files/plan/parser.js +0 -304
- package/files/plan/validators.d.ts +0 -52
- package/files/plan/validators.js +0 -187
- package/files/plan/writer.d.ts +0 -27
- package/files/plan/writer.js +0 -152
- package/files/sql/header.d.ts +0 -114
- package/files/sql/header.js +0 -266
- package/files/sql/index.d.ts +0 -2
- package/files/sql/index.js +0 -18
- package/files/sql/writer.d.ts +0 -12
- package/files/sql/writer.js +0 -114
- package/files/sql-scripts/index.d.ts +0 -1
- package/files/sql-scripts/reader.d.ts +0 -8
- package/files/sql-scripts/reader.js +0 -23
- package/files/types/index.d.ts +0 -46
- package/files/types/index.js +0 -17
- package/files/types/package.d.ts +0 -20
- package/utils/author.d.ts +0 -5
- package/utils/author.js +0 -14
- /package/esm/{files/types/package.js → rebundle/types.js} +0 -0
- /package/{files/types/package.js → rebundle/types.js} +0 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { copyFileSync, existsSync, mkdirSync, readdirSync, writeFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
|
|
4
|
+
import { mergeSqlStatements, packageModule } from '../packaging/package';
|
|
5
|
+
import { generatePlanContent } from '../slice/slice';
|
|
6
|
+
import { assembleChunkSql, rebundlePlan } from './rebundle';
|
|
7
|
+
export const SCRIPT_DIRS = ['deploy', 'revert', 'verify'];
|
|
8
|
+
/**
|
|
9
|
+
* Wrap a merged chunk body in a single transaction. Deploy/revert commit;
|
|
10
|
+
* verify rolls back (a verify script must leave no trace). The individual
|
|
11
|
+
* member files' own BEGIN/COMMIT were stripped during the merge, so each
|
|
12
|
+
* rebundled chunk deploys as exactly one transaction.
|
|
13
|
+
*/
|
|
14
|
+
function wrapTransaction(body, scriptType) {
|
|
15
|
+
const trimmed = body.trim();
|
|
16
|
+
const tail = scriptType === 'verify' ? 'ROLLBACK;' : 'COMMIT;';
|
|
17
|
+
return `BEGIN;\n\n${trimmed}\n\n${tail}\n`;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Merge one chunk's member scripts (in the correct order per direction) into a
|
|
21
|
+
* single deparsed, single-transaction migration string. Shared by the
|
|
22
|
+
* single-module (`rebundleModule`) and workspace (`rebundleWorkspace`) emitters.
|
|
23
|
+
*/
|
|
24
|
+
export async function mergeChunkScript(sourceDir, chunk, scriptType, opts = {}) {
|
|
25
|
+
const merged = await mergeSqlStatements(assembleChunkSql(sourceDir, chunk, scriptType), {
|
|
26
|
+
stripTransactions: true,
|
|
27
|
+
pretty: opts.pretty ?? true,
|
|
28
|
+
functionDelimiter: opts.functionDelimiter ?? '$EOFCODE$',
|
|
29
|
+
});
|
|
30
|
+
return wrapTransaction(merged.sql, scriptType);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Copy any top-level files (control, Makefile, package.json, README, ...) from
|
|
34
|
+
* the source module, excluding the plan and the per-change script directories
|
|
35
|
+
* which are regenerated. The rebundled module stays the same extension — same
|
|
36
|
+
* name, same control `requires` — only its internal change set collapses.
|
|
37
|
+
*/
|
|
38
|
+
function copyModuleMetadata(sourceDir, outputDir) {
|
|
39
|
+
for (const entry of readdirSync(sourceDir, { withFileTypes: true })) {
|
|
40
|
+
if (entry.isDirectory())
|
|
41
|
+
continue;
|
|
42
|
+
if (entry.name === 'pgpm.plan')
|
|
43
|
+
continue;
|
|
44
|
+
copyFileSync(join(sourceDir, entry.name), join(outputDir, entry.name));
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Materialize a rebundled module: merge each chunk's member scripts into a
|
|
49
|
+
* single deparsed migration (reusing `packageModule`'s merge engine), write the
|
|
50
|
+
* chunk-quotient plan, and verify the result is byte-identical when packaged.
|
|
51
|
+
*
|
|
52
|
+
* Reuses existing plumbing throughout — `rebundlePlan` for the chunk model,
|
|
53
|
+
* `mergeSqlStatements`/`packageModule` for statement merging and the gate,
|
|
54
|
+
* `generatePlanContent` for the chunk plan, and the source control/Makefile
|
|
55
|
+
* verbatim.
|
|
56
|
+
*/
|
|
57
|
+
export async function rebundleModule(sourceDir, options) {
|
|
58
|
+
const { outputDir, overwrite = false, pretty = true, functionDelimiter = '$EOFCODE$', ...strategy } = options;
|
|
59
|
+
if (existsSync(outputDir) && readdirSync(outputDir).length > 0 && !overwrite) {
|
|
60
|
+
throw new Error(`Output directory is not empty: ${outputDir}. Pass overwrite: true to replace.`);
|
|
61
|
+
}
|
|
62
|
+
const plan = rebundlePlan(sourceDir, strategy);
|
|
63
|
+
// Tags anchor on the last member of the chunk that sealed at them; remap each
|
|
64
|
+
// to its chunk name so `deploy --to @tag` still lands on a real change.
|
|
65
|
+
const parsed = parsePlanFile(join(sourceDir, 'pgpm.plan'));
|
|
66
|
+
const sourceTags = parsed.data?.tags ?? [];
|
|
67
|
+
const memberToChunk = new Map();
|
|
68
|
+
for (const chunk of plan.chunks) {
|
|
69
|
+
for (const member of chunk.deploy)
|
|
70
|
+
memberToChunk.set(member, chunk.name);
|
|
71
|
+
}
|
|
72
|
+
const remappedTags = sourceTags.map(tag => ({
|
|
73
|
+
...tag,
|
|
74
|
+
change: memberToChunk.get(tag.change) ?? tag.change,
|
|
75
|
+
}));
|
|
76
|
+
mkdirSync(outputDir, { recursive: true });
|
|
77
|
+
for (const dir of SCRIPT_DIRS)
|
|
78
|
+
mkdirSync(join(outputDir, dir), { recursive: true });
|
|
79
|
+
copyModuleMetadata(sourceDir, outputDir);
|
|
80
|
+
const written = [];
|
|
81
|
+
for (const chunk of plan.chunks) {
|
|
82
|
+
const paths = { chunk: chunk.name };
|
|
83
|
+
for (const dir of SCRIPT_DIRS) {
|
|
84
|
+
const merged = await mergeSqlStatements(assembleChunkSql(sourceDir, chunk, dir), {
|
|
85
|
+
stripTransactions: true,
|
|
86
|
+
pretty,
|
|
87
|
+
functionDelimiter,
|
|
88
|
+
});
|
|
89
|
+
const rel = join(dir, `${chunk.name}.sql`);
|
|
90
|
+
writeFileSync(join(outputDir, rel), wrapTransaction(merged.sql, dir));
|
|
91
|
+
paths[dir] = rel;
|
|
92
|
+
}
|
|
93
|
+
written.push(paths);
|
|
94
|
+
}
|
|
95
|
+
// Chunk-quotient plan: one change per chunk, deps are earlier chunk names.
|
|
96
|
+
const planEntries = plan.chunks.map(chunk => ({
|
|
97
|
+
name: chunk.name,
|
|
98
|
+
dependencies: chunk.dependencies,
|
|
99
|
+
}));
|
|
100
|
+
writeFileSync(join(outputDir, 'pgpm.plan'), generatePlanContent(plan.project, planEntries, remappedTags));
|
|
101
|
+
// Byte-identical gate: packaging the source and the rebundled module must
|
|
102
|
+
// produce the same consolidated extension SQL.
|
|
103
|
+
const sourcePkg = await packageModule(sourceDir, { pretty, functionDelimiter });
|
|
104
|
+
const outputPkg = await packageModule(outputDir, { pretty, functionDelimiter });
|
|
105
|
+
const invariant = {
|
|
106
|
+
ok: sourcePkg.sql === outputPkg.sql,
|
|
107
|
+
sourceDiff: !!sourcePkg.diff,
|
|
108
|
+
outputDiff: !!outputPkg.diff,
|
|
109
|
+
};
|
|
110
|
+
return { ...plan, outputDir, written, invariant };
|
|
111
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { readFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
import { getChanges } from '@pgpmjs/ast/files/plan/parser';
|
|
4
|
+
import { resolveWithPlan } from '../resolution/resolve';
|
|
5
|
+
import { buildDependencyGraph, buildPackageDependencies, computeDeployOrder, detectPackageCycle, extractPackageFromPath, } from '../slice/slice';
|
|
6
|
+
import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
|
|
7
|
+
/**
|
|
8
|
+
* Derive the boundary key for a change under the given strategy.
|
|
9
|
+
* Consecutive changes sharing a key may be merged into the same chunk.
|
|
10
|
+
*/
|
|
11
|
+
function boundaryKey(changeName, strategy) {
|
|
12
|
+
if (strategy.boundary === 'none')
|
|
13
|
+
return '';
|
|
14
|
+
const folderKey = () => extractPackageFromPath(changeName, strategy.depth ?? 1, strategy.prefixToStrip ?? 'schemas');
|
|
15
|
+
if (strategy.boundary === 'category') {
|
|
16
|
+
// Classifier/facts-driven seam: the caller decides each change's category;
|
|
17
|
+
// fall back to the folder key for changes it doesn't classify.
|
|
18
|
+
const category = strategy.categoryOf?.(changeName);
|
|
19
|
+
return category ?? folderKey();
|
|
20
|
+
}
|
|
21
|
+
return folderKey();
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Assign changes to chunks by walking the source plan in order and greedily
|
|
25
|
+
* accumulating consecutive changes that share a boundary key, sealing a chunk
|
|
26
|
+
* when the key changes, the size cap is reached, or a member carries a tag
|
|
27
|
+
* (tags mark points you can `deploy --to @tag`, so they must stay chunk seams).
|
|
28
|
+
*
|
|
29
|
+
* Because chunks are contiguous runs of the plan, member and chunk order both
|
|
30
|
+
* follow the source, which is what guarantees byte-identical output.
|
|
31
|
+
*/
|
|
32
|
+
function assignChunks(orderedChanges, graph, strategy) {
|
|
33
|
+
const chunks = [];
|
|
34
|
+
const seen = new Map();
|
|
35
|
+
const maxSize = strategy.maxChunkSize && strategy.maxChunkSize > 0 ? strategy.maxChunkSize : Infinity;
|
|
36
|
+
let current = null;
|
|
37
|
+
const seal = () => {
|
|
38
|
+
current = null;
|
|
39
|
+
};
|
|
40
|
+
for (const change of orderedChanges) {
|
|
41
|
+
const key = boundaryKey(change, strategy);
|
|
42
|
+
const changeHasTag = (graph.tags.get(change)?.length ?? 0) > 0;
|
|
43
|
+
if (current &&
|
|
44
|
+
current.key === key &&
|
|
45
|
+
current.members.length < maxSize) {
|
|
46
|
+
current.members.push(change);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
// Deterministic, collision-free chunk name: boundary key (or 'chunk'),
|
|
50
|
+
// suffixed with an ordinal when the same key splits across size caps.
|
|
51
|
+
const base = key || 'chunk';
|
|
52
|
+
const ordinal = (seen.get(base) ?? 0) + 1;
|
|
53
|
+
seen.set(base, ordinal);
|
|
54
|
+
const name = ordinal === 1 ? base : `${base}~${ordinal}`;
|
|
55
|
+
current = { name, members: [change], key };
|
|
56
|
+
chunks.push(current);
|
|
57
|
+
}
|
|
58
|
+
// A member that is a tag anchor seals the chunk after inclusion.
|
|
59
|
+
if (changeHasTag)
|
|
60
|
+
seal();
|
|
61
|
+
}
|
|
62
|
+
return chunks.map(({ name, members }) => ({ name, members }));
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Compute a rebundle plan for a pgpm module directory.
|
|
66
|
+
*
|
|
67
|
+
* Uses the existing plan parser, dependency graph, and package-dependency /
|
|
68
|
+
* deploy-order primitives from the slicer — chunks are treated exactly like
|
|
69
|
+
* packages for dependency and ordering purposes. No plan re-parsing or path
|
|
70
|
+
* logic is reinvented here.
|
|
71
|
+
*/
|
|
72
|
+
export function rebundlePlan(moduleDir, strategy = {}) {
|
|
73
|
+
const planPath = join(moduleDir, 'pgpm.plan');
|
|
74
|
+
const planResult = parsePlanFile(planPath);
|
|
75
|
+
if (!planResult.data) {
|
|
76
|
+
const msg = planResult.errors?.map(e => `Line ${e.line}: ${e.message}`).join('\n') || 'Unknown error';
|
|
77
|
+
throw new Error(`Failed to parse plan file: ${msg}`);
|
|
78
|
+
}
|
|
79
|
+
const graph = buildDependencyGraph(planResult.data);
|
|
80
|
+
const orderedChanges = planResult.data.changes.map(c => c.name);
|
|
81
|
+
const warnings = [];
|
|
82
|
+
const rawChunks = assignChunks(orderedChanges, graph, strategy);
|
|
83
|
+
// Reverse lookup change -> chunk, reusing slice's package-dep machinery.
|
|
84
|
+
const assignments = new Map();
|
|
85
|
+
const changeToChunk = new Map();
|
|
86
|
+
for (const chunk of rawChunks) {
|
|
87
|
+
assignments.set(chunk.name, new Set(chunk.members));
|
|
88
|
+
for (const member of chunk.members)
|
|
89
|
+
changeToChunk.set(member, chunk.name);
|
|
90
|
+
}
|
|
91
|
+
const chunkDeps = buildPackageDependencies(graph, assignments);
|
|
92
|
+
const cycle = detectPackageCycle(chunkDeps);
|
|
93
|
+
if (cycle) {
|
|
94
|
+
warnings.push({
|
|
95
|
+
type: 'cycle_detected',
|
|
96
|
+
message: `Chunk cycle detected: ${cycle.join(' -> ')}`,
|
|
97
|
+
suggestedAction: 'Widen the boundary or raise maxChunkSize so cyclic changes share a chunk',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
const deployOrder = computeDeployOrder(chunkDeps);
|
|
101
|
+
// Because chunks are contiguous runs of the source plan, the greedy creation
|
|
102
|
+
// order is already a valid deploy order. If the dependency-derived order
|
|
103
|
+
// disagrees, the boundary split a back-edge — surface it rather than silently
|
|
104
|
+
// reordering (that would break byte-identical output).
|
|
105
|
+
const creationOrder = rawChunks.map(c => c.name);
|
|
106
|
+
const orderMatches = deployOrder.length === creationOrder.length &&
|
|
107
|
+
deployOrder.every((name, i) => name === creationOrder[i]);
|
|
108
|
+
if (!orderMatches) {
|
|
109
|
+
warnings.push({
|
|
110
|
+
type: 'heavy_cross_deps',
|
|
111
|
+
message: 'Chunk deploy order differs from source order; a boundary split a dependency edge',
|
|
112
|
+
suggestedAction: 'Adjust the boundary/maxChunkSize so dependent changes stay contiguous',
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
const chunkByName = new Map(rawChunks.map(c => [c.name, c.members]));
|
|
116
|
+
const chunks = creationOrder.map(name => {
|
|
117
|
+
const members = chunkByName.get(name);
|
|
118
|
+
return {
|
|
119
|
+
name,
|
|
120
|
+
deploy: members,
|
|
121
|
+
verify: members,
|
|
122
|
+
revert: [...members].reverse(),
|
|
123
|
+
dependencies: [...(chunkDeps.get(name) ?? new Set())].sort(),
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
return {
|
|
127
|
+
chunks,
|
|
128
|
+
deployOrder: creationOrder,
|
|
129
|
+
warnings,
|
|
130
|
+
sourceChanges: planResult.data.changes,
|
|
131
|
+
project: planResult.data.package,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Assemble the merged SQL for one chunk in the given direction by concatenating
|
|
136
|
+
* its member script files — the same file-concatenation `resolveWithPlan` uses,
|
|
137
|
+
* just scoped to the chunk. Members are already correctly ordered per direction.
|
|
138
|
+
*/
|
|
139
|
+
export function assembleChunkSql(moduleDir, chunk, scriptType = 'deploy') {
|
|
140
|
+
const members = scriptType === 'revert' ? chunk.revert : scriptType === 'verify' ? chunk.verify : chunk.deploy;
|
|
141
|
+
const parts = [];
|
|
142
|
+
for (const change of members) {
|
|
143
|
+
parts.push(readFileSync(join(moduleDir, scriptType, `${change}.sql`), 'utf-8'));
|
|
144
|
+
}
|
|
145
|
+
return parts.join('\n');
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Byte-identical gate: assembling all chunks in deploy order must reproduce the
|
|
149
|
+
* module's original resolved output in every direction the engine cares about
|
|
150
|
+
* (deploy topological, verify in deploy order, revert reversed). This is the
|
|
151
|
+
* invariant that makes any granularity-dial position safe.
|
|
152
|
+
*/
|
|
153
|
+
export function verifyRebundleInvariant(moduleDir, result) {
|
|
154
|
+
const mismatches = [];
|
|
155
|
+
const assembled = (scriptType) => {
|
|
156
|
+
const chunks = scriptType === 'revert' ? [...result.chunks].reverse() : result.chunks;
|
|
157
|
+
return chunks.map(chunk => assembleChunkSql(moduleDir, chunk, scriptType)).join('\n');
|
|
158
|
+
};
|
|
159
|
+
// deploy / revert have canonical resolvers; verify concatenates in deploy order.
|
|
160
|
+
const originalVerify = getChanges(join(moduleDir, 'pgpm.plan'))
|
|
161
|
+
.map(change => readFileSync(join(moduleDir, 'verify', `${change}.sql`), 'utf-8'))
|
|
162
|
+
.join('\n');
|
|
163
|
+
if (assembled('deploy') !== resolveWithPlan(moduleDir, 'deploy'))
|
|
164
|
+
mismatches.push('deploy');
|
|
165
|
+
if (assembled('revert') !== resolveWithPlan(moduleDir, 'revert'))
|
|
166
|
+
mismatches.push('revert');
|
|
167
|
+
if (assembled('verify') !== originalVerify)
|
|
168
|
+
mismatches.push('verify');
|
|
169
|
+
return { ok: mismatches.length === 0, mismatches };
|
|
170
|
+
}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'fs';
|
|
2
|
+
import { basename, join } from 'path';
|
|
3
|
+
import { DEFAULT_TEMPLATE_REPO, scaffoldTemplate } from '../core/template-scaffold';
|
|
4
|
+
import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
|
|
5
|
+
import { mergeSqlStatements } from '../packaging/package';
|
|
6
|
+
import { resolveWithPlan } from '../resolution/resolve';
|
|
7
|
+
import { writeMinimalModule, writeMinimalWorkspace } from '../workspace/minimal';
|
|
8
|
+
import { mergeChunkScript } from './module';
|
|
9
|
+
import { rebundlePlan } from './rebundle';
|
|
10
|
+
/**
|
|
11
|
+
* Materialize a rebundled workspace: emit each chunk as its own tiny module
|
|
12
|
+
* (one merged change) under `packages/<chunk>/`, carrying cross-chunk deps via
|
|
13
|
+
* the control-file `requires` (and optionally a plan cross-reference).
|
|
14
|
+
*
|
|
15
|
+
* This is the "modular workspace" carve — the same monolith sliced into
|
|
16
|
+
* independently publishable module forks (e.g. a users module, an admin module).
|
|
17
|
+
* The emitted directory is a real, discoverable pgpm workspace: it reuses
|
|
18
|
+
* `writeMinimalWorkspace`/`writeMinimalModule` (the minimal deployable file set
|
|
19
|
+
* pgpm recognizes — `pgpm.json`, `pgpm.plan`, `<name>.control`, `Makefile`,
|
|
20
|
+
* `package.json`), `rebundlePlan` for the chunk model, and `mergeChunkScript`
|
|
21
|
+
* for the per-chunk merge.
|
|
22
|
+
*/
|
|
23
|
+
export async function rebundleWorkspace(sourceDir, options) {
|
|
24
|
+
const { outputDir, overwrite = false, pretty = true, functionDelimiter = '$EOFCODE$', crossChunkDepMode = 'control-only', initScaffold = false, templateRepo = DEFAULT_TEMPLATE_REPO, templateBranch, license = 'CONSTRUCTIVE', ...strategy } = options;
|
|
25
|
+
if (existsSync(outputDir) && readdirSync(outputDir).length > 0 && !overwrite) {
|
|
26
|
+
throw new Error(`Output directory is not empty: ${outputDir}. Pass overwrite: true to replace.`);
|
|
27
|
+
}
|
|
28
|
+
const plan = rebundlePlan(sourceDir, strategy);
|
|
29
|
+
// Remap tags onto their sealing chunk (each tag anchored a chunk boundary).
|
|
30
|
+
const parsed = parsePlanFile(join(sourceDir, 'pgpm.plan'));
|
|
31
|
+
const sourceTags = parsed.data?.tags ?? [];
|
|
32
|
+
const memberToChunk = new Map();
|
|
33
|
+
for (const chunk of plan.chunks) {
|
|
34
|
+
for (const member of chunk.deploy)
|
|
35
|
+
memberToChunk.set(member, chunk.name);
|
|
36
|
+
}
|
|
37
|
+
const remappedTags = sourceTags.map(tag => ({
|
|
38
|
+
...tag,
|
|
39
|
+
change: memberToChunk.get(tag.change) ?? tag.change,
|
|
40
|
+
}));
|
|
41
|
+
if (initScaffold) {
|
|
42
|
+
// Lay down the full `pgpm init` workspace shell (pgpm.json, pnpm-workspace,
|
|
43
|
+
// lerna.json, tsconfig, lint/format configs, CI); the merged pgpm files are
|
|
44
|
+
// written on top per module below.
|
|
45
|
+
await scaffoldTemplate({
|
|
46
|
+
fromPath: 'workspace',
|
|
47
|
+
outputDir,
|
|
48
|
+
templateRepo,
|
|
49
|
+
branch: templateBranch,
|
|
50
|
+
answers: workspaceAnswers(outputDir, license),
|
|
51
|
+
noTty: true,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
writeMinimalWorkspace(outputDir, { packages: ['packages/*'] });
|
|
56
|
+
}
|
|
57
|
+
const byDeployOrder = [...plan.chunks].sort((a, b) => plan.deployOrder.indexOf(a.name) - plan.deployOrder.indexOf(b.name));
|
|
58
|
+
const packages = [];
|
|
59
|
+
for (const chunk of byDeployOrder) {
|
|
60
|
+
const pkgRel = join('packages', chunk.name);
|
|
61
|
+
const pkgDir = join(outputDir, pkgRel);
|
|
62
|
+
if (initScaffold) {
|
|
63
|
+
// Scaffold the module's developer shell (package.json, jest.config.js,
|
|
64
|
+
// README, LICENSE, __tests__); writeMinimalModule overwrites the pgpm
|
|
65
|
+
// files (pgpm.plan, .control, Makefile, deploy/revert/verify) below.
|
|
66
|
+
await scaffoldTemplate({
|
|
67
|
+
fromPath: 'module',
|
|
68
|
+
outputDir: pkgDir,
|
|
69
|
+
templateRepo,
|
|
70
|
+
branch: templateBranch,
|
|
71
|
+
answers: moduleAnswers(chunk.name, license),
|
|
72
|
+
noTty: true,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
const scripts = {
|
|
76
|
+
[chunk.name]: {
|
|
77
|
+
deploy: await mergeChunkScript(sourceDir, chunk, 'deploy', { pretty, functionDelimiter }),
|
|
78
|
+
revert: await mergeChunkScript(sourceDir, chunk, 'revert', { pretty, functionDelimiter }),
|
|
79
|
+
verify: await mergeChunkScript(sourceDir, chunk, 'verify', { pretty, functionDelimiter }),
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
// Control `requires` always carries the module-level dependency; in
|
|
83
|
+
// 'change' mode the plan additionally records the fine-grained cross-ref.
|
|
84
|
+
const deps = chunk.dependencies;
|
|
85
|
+
const planChange = {
|
|
86
|
+
name: chunk.name,
|
|
87
|
+
dependencies: planChangeDeps(deps, crossChunkDepMode),
|
|
88
|
+
};
|
|
89
|
+
writeMinimalModule(pkgDir, {
|
|
90
|
+
name: chunk.name,
|
|
91
|
+
changes: [planChange],
|
|
92
|
+
scripts,
|
|
93
|
+
tags: remappedTags.filter(t => t.change === chunk.name),
|
|
94
|
+
requires: deps,
|
|
95
|
+
license,
|
|
96
|
+
overwrite: true,
|
|
97
|
+
// When scaffolded, keep the boilerplate's richer package.json.
|
|
98
|
+
writePackageJson: !initScaffold,
|
|
99
|
+
});
|
|
100
|
+
packages.push({ name: chunk.name, dir: pkgRel, dependencies: [...deps] });
|
|
101
|
+
}
|
|
102
|
+
const invariant = { ok: await checkWorkspaceInvariant(sourceDir, outputDir, packages, { pretty, functionDelimiter }) };
|
|
103
|
+
return { ...plan, outputDir, packages, crossChunkDepMode, invariant };
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* In 'change' mode, express each cross-chunk dep as a plan cross-reference
|
|
107
|
+
* (`<dep>:<dep>`, since each chunk-module has a single change named after it);
|
|
108
|
+
* in 'control-only' mode the plan carries no deps — the control `requires`
|
|
109
|
+
* governs ordering.
|
|
110
|
+
*/
|
|
111
|
+
function planChangeDeps(deps, mode) {
|
|
112
|
+
if (mode === 'control-only')
|
|
113
|
+
return [];
|
|
114
|
+
return deps.map(dep => `${dep}:${dep}`);
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Non-interactive answers for the `pgpm init` workspace template. Values are
|
|
118
|
+
* deterministic placeholders (the generated pgpm files are the real payload);
|
|
119
|
+
* the workspace name derives from the output directory.
|
|
120
|
+
*/
|
|
121
|
+
function workspaceAnswers(outputDir, license) {
|
|
122
|
+
const name = basename(outputDir) || 'rebundled-workspace';
|
|
123
|
+
return {
|
|
124
|
+
name,
|
|
125
|
+
fullName: 'Constructive',
|
|
126
|
+
email: 'noreply@constructive.io',
|
|
127
|
+
moduleName: name,
|
|
128
|
+
username: 'constructive-io',
|
|
129
|
+
repoName: name,
|
|
130
|
+
license,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Non-interactive answers for the `pgpm init` module template. */
|
|
134
|
+
function moduleAnswers(name, license) {
|
|
135
|
+
return {
|
|
136
|
+
name,
|
|
137
|
+
moduleName: name,
|
|
138
|
+
moduleDesc: `${name} module`,
|
|
139
|
+
description: `${name} module`,
|
|
140
|
+
repoName: name,
|
|
141
|
+
fullName: 'Constructive',
|
|
142
|
+
email: 'noreply@constructive.io',
|
|
143
|
+
username: 'constructive-io',
|
|
144
|
+
access: 'public',
|
|
145
|
+
license,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Byte-identical gate for a workspace: concatenate every package's deploy
|
|
150
|
+
* script in workspace deploy order, merge it, and compare against the merged
|
|
151
|
+
* original module deploy output. Both go through the same `mergeSqlStatements`
|
|
152
|
+
* pipeline, so equality proves the carve preserved the deployed statements and
|
|
153
|
+
* their order.
|
|
154
|
+
*/
|
|
155
|
+
async function checkWorkspaceInvariant(sourceDir, outputDir, packages, opts) {
|
|
156
|
+
const concatenated = packages
|
|
157
|
+
.map(p => readFileSync(join(outputDir, p.dir, 'deploy', `${p.name}.sql`), 'utf-8'))
|
|
158
|
+
.join('\n');
|
|
159
|
+
const workspaceMerged = await mergeSqlStatements(concatenated, {
|
|
160
|
+
stripTransactions: true,
|
|
161
|
+
pretty: opts.pretty,
|
|
162
|
+
functionDelimiter: opts.functionDelimiter,
|
|
163
|
+
});
|
|
164
|
+
const sourceMerged = await mergeSqlStatements(resolveWithPlan(sourceDir, 'deploy'), {
|
|
165
|
+
stripTransactions: true,
|
|
166
|
+
pretty: opts.pretty,
|
|
167
|
+
functionDelimiter: opts.functionDelimiter,
|
|
168
|
+
});
|
|
169
|
+
return workspaceMerged.sql === sourceMerged.sql;
|
|
170
|
+
}
|
package/esm/refactor/rename.js
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmdirSync, statSync, writeFileSync } from 'fs';
|
|
2
2
|
import { dirname, join, relative, sep } from 'path';
|
|
3
|
-
import { parsePlanFileSimple } from '
|
|
4
|
-
import { parsePgpmHeader, renameInHeader, writePgpmScript } from '
|
|
3
|
+
import { parsePlanFileSimple } from '@pgpmjs/ast/files/plan/parser';
|
|
4
|
+
import { parsePgpmHeader, renameInHeader, writePgpmScript } from '@pgpmjs/ast/files/sql/header';
|
|
5
|
+
import { renameInPlanContent } from '@pgpmjs/ast/plan-rename';
|
|
6
|
+
// Re-exported from @pgpmjs/ast so existing `@pgpmjs/core` consumers keep importing it here.
|
|
7
|
+
export { renameInPlanContent };
|
|
5
8
|
const SCRIPT_DIRS = ['deploy', 'revert', 'verify'];
|
|
6
9
|
function escapeRe(str) {
|
|
7
10
|
return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
@@ -59,31 +62,6 @@ export function validateRenames(moduleDir, renames) {
|
|
|
59
62
|
targets.add(to);
|
|
60
63
|
}
|
|
61
64
|
}
|
|
62
|
-
/**
|
|
63
|
-
* Rewrite change names in a pgpm.plan's content according to a rename map.
|
|
64
|
-
* Textual and format-preserving: only the change-name token at the start of a
|
|
65
|
-
* change line, plain (same-package) dependency refs inside `[...]`, and tag
|
|
66
|
-
* lines' change field are rewritten; timestamps, planners, comments,
|
|
67
|
-
* cross-package refs, and tag refs are untouched.
|
|
68
|
-
*/
|
|
69
|
-
export function renameInPlanContent(content, renames) {
|
|
70
|
-
const froms = Array.from(renames.keys()).sort((a, b) => b.length - a.length);
|
|
71
|
-
return content
|
|
72
|
-
.split('\n')
|
|
73
|
-
.map(line => {
|
|
74
|
-
const trimmed = line.trim();
|
|
75
|
-
if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('%'))
|
|
76
|
-
return line;
|
|
77
|
-
let result = line;
|
|
78
|
-
for (const from of froms) {
|
|
79
|
-
const to = renames.get(from);
|
|
80
|
-
const re = new RegExp(`(^|[\\s\\[])${escapeRe(from)}(?=$|[\\s\\]@])`, 'g');
|
|
81
|
-
result = result.replace(re, `$1${to}`);
|
|
82
|
-
}
|
|
83
|
-
return result;
|
|
84
|
-
})
|
|
85
|
-
.join('\n');
|
|
86
|
-
}
|
|
87
65
|
/**
|
|
88
66
|
* Atomically rename/move changes within a pgpm module: the coupled 4-way
|
|
89
67
|
* rewrite of (1) deploy/revert/verify script files on disk, (2) the moved
|
package/esm/resolution/deps.js
CHANGED
|
@@ -2,8 +2,8 @@ import { readFileSync } from 'fs';
|
|
|
2
2
|
import { sync as glob } from 'glob';
|
|
3
3
|
import { join, relative } from 'path';
|
|
4
4
|
import { PgpmPackage } from '../core/class/pgpm';
|
|
5
|
-
import { parsePlanFile } from '
|
|
6
|
-
import { scanDeployScript } from '
|
|
5
|
+
import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
|
|
6
|
+
import { scanDeployScript } from '@pgpmjs/ast/files/sql/header';
|
|
7
7
|
import { errors } from '@pgpmjs/types';
|
|
8
8
|
/**
|
|
9
9
|
* Core dependency resolution algorithm that handles circular dependency detection
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from 'fs';
|
|
2
|
-
import { getChanges, getExtensionName } from '
|
|
3
|
-
import { parsePlanFile } from '
|
|
2
|
+
import { getChanges, getExtensionName } from '@pgpmjs/ast/files';
|
|
3
|
+
import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
|
|
4
4
|
import { resolveDependencies } from './deps';
|
|
5
5
|
import { errors } from '@pgpmjs/types';
|
|
6
6
|
/**
|
package/esm/slice/slice.js
CHANGED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { generatePlanContent } from '../slice/slice';
|
|
4
|
+
const SCRIPT_DIRS = ['deploy', 'revert', 'verify'];
|
|
5
|
+
/**
|
|
6
|
+
* The minimal set of files pgpm needs to recognize and deploy a module:
|
|
7
|
+
* `pgpm.plan` (module marker + change order), `<name>.control` (extension
|
|
8
|
+
* metadata), `Makefile` (PGXS packaging), `package.json`, and the
|
|
9
|
+
* deploy/revert/verify scripts. Mirrors what `pgpm init` scaffolds, minus the
|
|
10
|
+
* network-fetched boilerplate (README/LICENSE/jest/tests/lint configs).
|
|
11
|
+
*/
|
|
12
|
+
export function writeMinimalModule(moduleDir, options) {
|
|
13
|
+
const { name, changes, scripts, tags = [], requires = [], version = '0.0.1', license = 'CONSTRUCTIVE', overwrite = false, writePackageJson = true, } = options;
|
|
14
|
+
if (fs.existsSync(moduleDir) && fs.readdirSync(moduleDir).length > 0 && !overwrite) {
|
|
15
|
+
throw new Error(`Module directory is not empty: ${moduleDir}. Pass overwrite: true to replace.`);
|
|
16
|
+
}
|
|
17
|
+
for (const dir of SCRIPT_DIRS) {
|
|
18
|
+
fs.mkdirSync(path.join(moduleDir, dir), { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
for (const change of changes) {
|
|
21
|
+
const changeScripts = scripts[change.name];
|
|
22
|
+
if (!changeScripts) {
|
|
23
|
+
throw new Error(`Missing scripts for change "${change.name}" in module "${name}"`);
|
|
24
|
+
}
|
|
25
|
+
fs.writeFileSync(path.join(moduleDir, 'deploy', `${change.name}.sql`), changeScripts.deploy);
|
|
26
|
+
fs.writeFileSync(path.join(moduleDir, 'revert', `${change.name}.sql`), changeScripts.revert);
|
|
27
|
+
fs.writeFileSync(path.join(moduleDir, 'verify', `${change.name}.sql`), changeScripts.verify ?? `-- Verify ${change.name}\n\nBEGIN;\n\nSELECT 1;\n\nROLLBACK;\n`);
|
|
28
|
+
}
|
|
29
|
+
fs.writeFileSync(path.join(moduleDir, 'pgpm.plan'), generatePlanContent(name, changes, tags));
|
|
30
|
+
fs.writeFileSync(path.join(moduleDir, `${name}.control`), generateModuleControl(name, requires, version));
|
|
31
|
+
fs.writeFileSync(path.join(moduleDir, 'Makefile'), generateModuleMakefile(name, version));
|
|
32
|
+
if (writePackageJson) {
|
|
33
|
+
fs.writeFileSync(path.join(moduleDir, 'package.json'), JSON.stringify({ name, version, description: `${name} module`, license }, null, 2) + '\n');
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Write the minimal workspace marker (`pgpm.json`) so pgpm discovers the
|
|
38
|
+
* directory as a workspace. This is what `getWorkspacePath` walks up to find.
|
|
39
|
+
*/
|
|
40
|
+
export function writeMinimalWorkspace(workspaceDir, options = {}) {
|
|
41
|
+
const { packages = ['packages/*'], overwrite = true } = options;
|
|
42
|
+
const configPath = path.join(workspaceDir, 'pgpm.json');
|
|
43
|
+
if (fs.existsSync(configPath) && !overwrite)
|
|
44
|
+
return;
|
|
45
|
+
fs.mkdirSync(workspaceDir, { recursive: true });
|
|
46
|
+
fs.writeFileSync(configPath, JSON.stringify({ packages }, null, 2) + '\n');
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Full extension control file, matching the shape `pgpm init` emits (comment,
|
|
50
|
+
* default_version, module_pathname, requires, relocatable, superuser).
|
|
51
|
+
*/
|
|
52
|
+
export function generateModuleControl(name, requires = [], version = '0.0.1') {
|
|
53
|
+
let content = `# ${name} extension\n`;
|
|
54
|
+
content += `comment = '${name} extension'\n`;
|
|
55
|
+
content += `default_version = '${version}'\n`;
|
|
56
|
+
content += `module_pathname = '$libdir/${name}'\n`;
|
|
57
|
+
if (requires.length > 0) {
|
|
58
|
+
content += `requires = '${requires.join(',')}'\n`;
|
|
59
|
+
}
|
|
60
|
+
content += `relocatable = false\n`;
|
|
61
|
+
content += `superuser = false\n`;
|
|
62
|
+
return content;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* PGXS Makefile for `pgpm package`/`make install`.
|
|
66
|
+
*/
|
|
67
|
+
export function generateModuleMakefile(name, version = '0.0.1') {
|
|
68
|
+
return (`EXTENSION = ${name}\n` +
|
|
69
|
+
`DATA = sql/${name}--${version}.sql\n\n` +
|
|
70
|
+
`PG_CONFIG = pg_config\n` +
|
|
71
|
+
`PGXS := $(shell $(PG_CONFIG) --pgxs)\n` +
|
|
72
|
+
`include $(PGXS)\n`);
|
|
73
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export * from './core/class/pgpm';
|
|
2
2
|
export * from './slice';
|
|
3
|
+
export * from './rebundle';
|
|
3
4
|
export * from './extensions/extensions';
|
|
4
5
|
export * from './modules/modules';
|
|
5
6
|
export * from './packaging/package';
|
|
@@ -8,16 +9,19 @@ export * from './resolution/deps';
|
|
|
8
9
|
export * from './resolution/resolve';
|
|
9
10
|
export * from './workspace/paths';
|
|
10
11
|
export * from './workspace/utils';
|
|
12
|
+
export * from './workspace/minimal';
|
|
11
13
|
export * from './core/template-scaffold';
|
|
12
14
|
export * from './core/boilerplate-types';
|
|
13
15
|
export * from './core/boilerplate-scanner';
|
|
14
|
-
export * from '
|
|
16
|
+
export * from '@pgpmjs/ast/files';
|
|
17
|
+
export * from '@pgpmjs/ast/module';
|
|
18
|
+
export * from './bundle';
|
|
15
19
|
export * from './refactor';
|
|
16
20
|
export { cleanSql } from './migrate/clean';
|
|
17
21
|
export { PgpmMigrate } from './migrate/client';
|
|
18
22
|
export { PgpmInit } from './init/client';
|
|
19
23
|
export * from './roles';
|
|
20
|
-
export { parseAuthor } from '
|
|
24
|
+
export { parseAuthor } from '@pgpmjs/ast';
|
|
21
25
|
export { DeployOptions, DeployResult, MigrateChange, MigratePlanFile, RevertOptions, RevertResult, StatusResult, VerifyOptions, VerifyResult } from './migrate/types';
|
|
22
26
|
export { hashFile, hashString } from './migrate/utils/hash';
|
|
23
27
|
export { executeQuery, TransactionContext, TransactionOptions, withTransaction } from './migrate/utils/transaction';
|
package/index.js
CHANGED
|
@@ -17,6 +17,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
17
17
|
exports.withTransaction = exports.executeQuery = exports.hashString = exports.hashFile = exports.parseAuthor = exports.PgpmInit = exports.PgpmMigrate = exports.cleanSql = void 0;
|
|
18
18
|
__exportStar(require("./core/class/pgpm"), exports);
|
|
19
19
|
__exportStar(require("./slice"), exports);
|
|
20
|
+
__exportStar(require("./rebundle"), exports);
|
|
20
21
|
__exportStar(require("./extensions/extensions"), exports);
|
|
21
22
|
__exportStar(require("./modules/modules"), exports);
|
|
22
23
|
__exportStar(require("./packaging/package"), exports);
|
|
@@ -25,11 +26,14 @@ __exportStar(require("./resolution/deps"), exports);
|
|
|
25
26
|
__exportStar(require("./resolution/resolve"), exports);
|
|
26
27
|
__exportStar(require("./workspace/paths"), exports);
|
|
27
28
|
__exportStar(require("./workspace/utils"), exports);
|
|
29
|
+
__exportStar(require("./workspace/minimal"), exports);
|
|
28
30
|
__exportStar(require("./core/template-scaffold"), exports);
|
|
29
31
|
__exportStar(require("./core/boilerplate-types"), exports);
|
|
30
32
|
__exportStar(require("./core/boilerplate-scanner"), exports);
|
|
31
|
-
//
|
|
32
|
-
__exportStar(require("
|
|
33
|
+
// Re-export the module AST layer (moved to the @pgpmjs/ast leaf package)
|
|
34
|
+
__exportStar(require("@pgpmjs/ast/files"), exports);
|
|
35
|
+
__exportStar(require("@pgpmjs/ast/module"), exports);
|
|
36
|
+
__exportStar(require("./bundle"), exports);
|
|
33
37
|
__exportStar(require("./refactor"), exports);
|
|
34
38
|
var clean_1 = require("./migrate/clean");
|
|
35
39
|
Object.defineProperty(exports, "cleanSql", { enumerable: true, get: function () { return clean_1.cleanSql; } });
|
|
@@ -38,8 +42,8 @@ Object.defineProperty(exports, "PgpmMigrate", { enumerable: true, get: function
|
|
|
38
42
|
var client_2 = require("./init/client");
|
|
39
43
|
Object.defineProperty(exports, "PgpmInit", { enumerable: true, get: function () { return client_2.PgpmInit; } });
|
|
40
44
|
__exportStar(require("./roles"), exports);
|
|
41
|
-
var
|
|
42
|
-
Object.defineProperty(exports, "parseAuthor", { enumerable: true, get: function () { return
|
|
45
|
+
var ast_1 = require("@pgpmjs/ast");
|
|
46
|
+
Object.defineProperty(exports, "parseAuthor", { enumerable: true, get: function () { return ast_1.parseAuthor; } });
|
|
43
47
|
var hash_1 = require("./migrate/utils/hash");
|
|
44
48
|
Object.defineProperty(exports, "hashFile", { enumerable: true, get: function () { return hash_1.hashFile; } });
|
|
45
49
|
Object.defineProperty(exports, "hashString", { enumerable: true, get: function () { return hash_1.hashString; } });
|