@santi020k/lumen 3.0.1 → 4.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/README.md +207 -3
- package/dist/cli.js +49 -5
- package/dist/consumer-upgrade-audit.d.ts +10 -0
- package/dist/consumer-upgrade-audit.d.ts.map +1 -0
- package/dist/consumer-upgrade-audit.js +52 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/installer.d.ts.map +1 -1
- package/dist/installer.js +16 -0
- package/dist/integration-diagnostics.d.ts.map +1 -1
- package/dist/integration-diagnostics.js +199 -3
- package/dist/registry-component-name.d.ts +2 -0
- package/dist/registry-component-name.d.ts.map +1 -0
- package/dist/registry-component-name.js +53 -0
- package/dist/registry-data.d.ts +339 -18
- package/dist/registry-data.d.ts.map +1 -1
- package/dist/registry-data.js +789 -3
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +11 -9
- package/dist/source-script-ranges.d.ts +3 -0
- package/dist/source-script-ranges.d.ts.map +1 -0
- package/dist/source-script-ranges.js +41 -0
- package/dist/v2-migration.d.ts +38 -0
- package/dist/v2-migration.d.ts.map +1 -1
- package/dist/v2-migration.js +26 -14
- package/dist/v4-migration.d.ts +26 -0
- package/dist/v4-migration.d.ts.map +1 -0
- package/dist/v4-migration.js +272 -0
- package/dist/version-migration-dependencies.d.ts +8 -0
- package/dist/version-migration-dependencies.d.ts.map +1 -0
- package/dist/version-migration-dependencies.js +10 -0
- package/dist/version-migration-source.d.ts +4 -0
- package/dist/version-migration-source.d.ts.map +1 -0
- package/dist/version-migration-source.js +281 -0
- package/dist/version-migration.d.ts +34 -0
- package/dist/version-migration.d.ts.map +1 -0
- package/dist/version-migration.js +158 -0
- package/native-components.json +563 -16
- package/package.json +26 -11
- package/release-manifest.json +22 -17
- package/styles/critical.css +634 -61
- package/styles/motion.css +61 -0
- package/styles/world-map.css +30 -0
- package/styles.css +1736 -455
- package/templates/astro/advanced-fields/src/lumen/advanced-fields.astro +35 -0
- package/templates/astro/ai-docs/llms.txt +3 -0
- package/templates/astro/analytics-dashboard/src/lumen/analytics-dashboard.astro +110 -0
- package/templates/astro/auth-onboarding/src/lumen/auth-onboarding.astro +107 -0
- package/templates/astro/command-center/src/lumen/command-center.astro +34 -0
- package/templates/astro/commerce-dashboard/src/lumen/commerce-dashboard.astro +108 -0
- package/templates/astro/content-flow-actions/src/lumen/content-flow-actions.astro +10 -0
- package/templates/astro/content-flow-header/src/lumen/content-flow-header.astro +14 -0
- package/templates/astro/content-flow-list/src/lumen/content-flow-list.astro +13 -0
- package/templates/astro/content-flow-settings/src/lumen/content-flow-settings.astro +17 -0
- package/templates/astro/data-collections/src/lumen/data-collections.astro +52 -0
- package/templates/astro/feature-preview/src/lumen/feature-preview.astro +32 -0
- package/templates/astro/guided-onboarding/src/lumen/guided-onboarding.astro +35 -0
- package/templates/astro/interactive-pricing/src/lumen/interactive-pricing.astro +32 -0
- package/templates/astro/media-workspace/src/lumen/adjustment-controls.astro +89 -0
- package/templates/astro/media-workspace/src/lumen/media-processing.astro +47 -0
- package/templates/astro/media-workspace/src/lumen/media-workspace.astro +77 -0
- package/templates/astro/page-header/src/lumen/page-header.astro +41 -0
- package/templates/astro/project-workspace/src/lumen/project-workspace.astro +103 -0
- package/templates/astro/rich-text-editor/src/lumen/rich-text-editor.astro +21 -0
- package/templates/astro/saas-admin/src/lumen/saas-admin.astro +110 -0
- package/templates/astro/scheduler/src/lumen/scheduler.astro +36 -0
- package/templates/astro/section-header/src/lumen/section-header.astro +35 -0
- package/templates/astro/theme-builder/src/lumen/theme-builder.astro +28 -0
- package/templates/elements/advanced-fields/src/lumen/advanced-fields.html +25 -0
- package/templates/elements/analytics-dashboard/src/lumen/analytics-dashboard.html +28 -0
- package/templates/elements/auth-onboarding/src/lumen/auth-onboarding.html +79 -0
- package/templates/elements/command-center/src/lumen/command-center.html +15 -0
- package/templates/elements/commerce-dashboard/src/lumen/commerce-dashboard.html +24 -0
- package/templates/elements/content-flow-actions/src/lumen/content-flow-actions.html +11 -0
- package/templates/elements/content-flow-header/src/lumen/content-flow-header.html +15 -0
- package/templates/elements/content-flow-list/src/lumen/content-flow-list.html +14 -0
- package/templates/elements/content-flow-settings/src/lumen/content-flow-settings.html +18 -0
- package/templates/elements/data-collections/src/lumen/data-collections.html +31 -0
- package/templates/elements/feature-preview/src/lumen/feature-preview.html +13 -0
- package/templates/elements/guided-onboarding/src/lumen/guided-onboarding.html +16 -0
- package/templates/elements/interactive-pricing/src/lumen/interactive-pricing.html +13 -0
- package/templates/elements/media-workspace/src/lumen/media-workspace.html +57 -0
- package/templates/elements/media-workspace/src/lumen/media-workspace.ts +163 -0
- package/templates/elements/page-header/src/lumen/page-header.html +20 -0
- package/templates/elements/project-workspace/src/lumen/project-workspace.html +17 -0
- package/templates/elements/rich-text-editor/src/lumen/rich-text-editor.html +17 -0
- package/templates/elements/saas-admin/src/lumen/saas-admin.html +18 -0
- package/templates/elements/scheduler/src/lumen/scheduler.html +27 -0
- package/templates/elements/section-header/src/lumen/section-header.html +21 -0
- package/templates/elements/theme-builder/src/lumen/theme-builder.html +59 -0
- package/templates/react/advanced-fields/src/lumen/advanced-fields.tsx +37 -0
- package/templates/react/analytics-dashboard/src/lumen/analytics-dashboard.tsx +143 -0
- package/templates/react/auth-onboarding/src/lumen/auth-onboarding.tsx +129 -0
- package/templates/react/command-center/src/lumen/command-center.tsx +85 -0
- package/templates/react/commerce-dashboard/src/lumen/commerce-dashboard.tsx +148 -0
- package/templates/react/content-flow-actions/src/lumen/content-flow-actions.tsx +11 -0
- package/templates/react/content-flow-header/src/lumen/content-flow-header.tsx +14 -0
- package/templates/react/content-flow-list/src/lumen/content-flow-list.tsx +19 -0
- package/templates/react/content-flow-settings/src/lumen/content-flow-settings.tsx +26 -0
- package/templates/react/data-collections/src/lumen/data-collections.tsx +60 -0
- package/templates/react/feature-preview/src/lumen/feature-preview.tsx +42 -0
- package/templates/react/guided-onboarding/src/lumen/guided-onboarding.tsx +100 -0
- package/templates/react/import-review/src/lumen/import-review.tsx +150 -0
- package/templates/react/interactive-pricing/src/lumen/interactive-pricing.tsx +60 -0
- package/templates/react/media-workspace/src/lumen/adjustment-controls.tsx +61 -0
- package/templates/react/media-workspace/src/lumen/media-processing.tsx +43 -0
- package/templates/react/media-workspace/src/lumen/media-workspace.tsx +100 -0
- package/templates/react/operational-records/src/lumen/operational-records.tsx +92 -0
- package/templates/react/page-header/src/lumen/page-header.tsx +41 -0
- package/templates/react/project-workspace/src/lumen/project-workspace.tsx +112 -0
- package/templates/react/record-workspace/src/lumen/record-workspace.tsx +67 -0
- package/templates/react/review-workflow/src/lumen/review-workflow.tsx +202 -0
- package/templates/react/rich-text-editor/src/lumen/rich-text-editor.tsx +33 -0
- package/templates/react/saas-admin/src/lumen/saas-admin.tsx +119 -0
- package/templates/react/scheduler/src/lumen/scheduler.tsx +45 -0
- package/templates/react/section-header/src/lumen/section-header.tsx +33 -0
- package/templates/react/styles.d.ts +1 -0
- package/templates/react/theme-builder/src/lumen/theme-builder.tsx +57 -0
- package/templates/react/tsconfig.json +14 -0
- package/templates/react/validated-form/src/lumen/validated-form.tsx +166 -0
- package/templates/shared/common/src/lumen/lumen-template.css +247 -0
- package/templates/shared/media-workspace/src/lumen/media-workspace.css +14 -0
- package/templates/shared/visual-blocks/src/lumen/product-blocks.ts +224 -0
- package/v4-migration.json +447 -0
package/dist/registry.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,OAAO,KAAK,EACV,aAAa,EACb,sBAAsB,EACtB,8BAA8B,EAC9B,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,aAAa,EAAE,CAAA;AAExB,YAAY,EACV,aAAa,EACb,sBAAsB,EACtB,8BAA8B,EAC9B,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACzB,CAAA;AAwBD,eAAO,MAAM,uBAAuB,GAAI,WAAU,aAA6B,KAAG,kBAAkB,EAGnG,CAAA;AAED,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,EACZ,WAAU,aAA6B,KACtC,kBAAkB,GAAG,SAQvB,CAAA;
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,OAAO,KAAK,EACV,aAAa,EACb,sBAAsB,EACtB,8BAA8B,EAC9B,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACzB,MAAM,qBAAqB,CAAA;AAE5B,OAAO,EAAE,aAAa,EAAE,CAAA;AAExB,YAAY,EACV,aAAa,EACb,sBAAsB,EACtB,8BAA8B,EAC9B,kBAAkB,EAClB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACzB,CAAA;AAwBD,eAAO,MAAM,uBAAuB,GAAI,WAAU,aAA6B,KAAG,kBAAkB,EAGnG,CAAA;AAED,eAAO,MAAM,oBAAoB,GAC/B,MAAM,MAAM,EACZ,WAAU,aAA6B,KACtC,kBAAkB,GAAG,SAQvB,CAAA;AAsKD,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,GAAG,GAAG,EACpB,UAAS,wBAA6B,KACrC,OAAO,CAAC,aAAa,CAsBvB,CAAA;AAED,OAAO,EACL,oBAAoB,EACpB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,cAAc,EACnB,KAAK,kBAAkB,EACxB,MAAM,gBAAgB,CAAA"}
|
package/dist/registry.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/* eslint-disable complexity */
|
|
2
1
|
import { readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import { isSafeRegistryComponentName } from './registry-component-name.js';
|
|
3
3
|
import { lumenRegistry } from './registry-data.js';
|
|
4
4
|
import { isSafeRegistryFilePath } from './registry-path.js';
|
|
5
5
|
export { lumenRegistry };
|
|
@@ -50,30 +50,32 @@ const isRegistryItem = (value) => {
|
|
|
50
50
|
(item.components === undefined || isStringArray(item.components)) &&
|
|
51
51
|
(item.files === undefined || isRegistryFileArray(item.files)));
|
|
52
52
|
};
|
|
53
|
+
const isNonEmptyString = (value) => typeof value === 'string' && value.trim().length > 0;
|
|
53
54
|
const isRegistryComponent = (value) => {
|
|
54
55
|
if (!value || typeof value !== 'object')
|
|
55
56
|
return false;
|
|
56
57
|
const component = value;
|
|
57
|
-
return (
|
|
58
|
+
return (isSafeRegistryComponentName(component.name) &&
|
|
58
59
|
component.type === 'component' &&
|
|
59
|
-
|
|
60
|
-
|
|
60
|
+
isNonEmptyString(component.description) &&
|
|
61
|
+
isNonEmptyString(component.category) &&
|
|
61
62
|
isRegistryFileArray(component.files) &&
|
|
62
63
|
(component.dependencies === undefined || isStringArray(component.dependencies)));
|
|
63
64
|
};
|
|
65
|
+
const isRegistryComponents = (value) => (Array.isArray(value) && value.every((component) => isRegistryComponent(component)));
|
|
66
|
+
const isPositiveSafeInteger = (value) => (typeof value === 'number' && Number.isSafeInteger(value) && value > 0);
|
|
64
67
|
const isLumenRegistry = (value) => {
|
|
65
68
|
if (!value || typeof value !== 'object')
|
|
66
69
|
return false;
|
|
67
70
|
const registry = value;
|
|
68
|
-
return (
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
typeof registry.description === 'string' && registry.description.trim().length > 0 &&
|
|
71
|
+
return (isNonEmptyString(registry.name) &&
|
|
72
|
+
isPositiveSafeInteger(registry.version) &&
|
|
73
|
+
isNonEmptyString(registry.description) &&
|
|
72
74
|
isStringArray(registry.packages) &&
|
|
73
75
|
Array.isArray(registry.items) &&
|
|
74
76
|
registry.items.every(item => isRegistryItem(item)) &&
|
|
75
77
|
(registry.components === undefined ||
|
|
76
|
-
(
|
|
78
|
+
isRegistryComponents(registry.components)));
|
|
77
79
|
};
|
|
78
80
|
const getResponseBody = (response) => response.body;
|
|
79
81
|
const readBoundedResponse = async (response, maxBytes) => {
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** Use compiler grammar for regex/division; callers fail closed when the parser exceeds its nesting limit. */
|
|
2
|
+
export declare const scriptRegexRanges: (source: string, file: string) => ReadonlyMap<number, number> | undefined;
|
|
3
|
+
//# sourceMappingURL=source-script-ranges.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"source-script-ranges.d.ts","sourceRoot":"","sources":["../src/source-script-ranges.ts"],"names":[],"mappings":"AAsBA,8GAA8G;AAC9G,eAAO,MAAM,iBAAiB,GAAI,QAAQ,MAAM,EAAE,MAAM,MAAM,KAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SA0B9F,CAAA"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createSourceFile, ScriptKind, ScriptTarget, SyntaxKind } from 'typescript';
|
|
2
|
+
const frontmatter = (source) => {
|
|
3
|
+
if (!source.startsWith('---'))
|
|
4
|
+
return { offset: 0, source: '' };
|
|
5
|
+
const end = source.indexOf('\n---', 3);
|
|
6
|
+
return { offset: 3, source: source.slice(3, end < 0 ? source.length : end) };
|
|
7
|
+
};
|
|
8
|
+
const parseRoot = (source, file) => {
|
|
9
|
+
const jsx = ['.tsx', '.jsx'].some(extension => file.endsWith(extension));
|
|
10
|
+
try {
|
|
11
|
+
return createSourceFile(file, source, ScriptTarget.Latest, false, jsx ? ScriptKind.TSX : ScriptKind.TS);
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (!(error instanceof RangeError))
|
|
15
|
+
throw error;
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/** Use compiler grammar for regex/division; callers fail closed when the parser exceeds its nesting limit. */
|
|
20
|
+
export const scriptRegexRanges = (source, file) => {
|
|
21
|
+
if (['.html', '.htm', '.css', '.swift', '.kt', '.kts'].some(extension => file.endsWith(extension)))
|
|
22
|
+
return new Map();
|
|
23
|
+
const fragment = file.endsWith('.astro') ? frontmatter(source) : { offset: 0, source };
|
|
24
|
+
const root = parseRoot(fragment.source, file);
|
|
25
|
+
if (!root)
|
|
26
|
+
return undefined;
|
|
27
|
+
const pending = [root];
|
|
28
|
+
const ranges = new Map();
|
|
29
|
+
while (pending.length > 0) {
|
|
30
|
+
const node = pending.pop();
|
|
31
|
+
if (!node)
|
|
32
|
+
continue;
|
|
33
|
+
if (node.kind === SyntaxKind.RegularExpressionLiteral) {
|
|
34
|
+
ranges.set(node.getStart(root) + fragment.offset, node.end + fragment.offset);
|
|
35
|
+
}
|
|
36
|
+
node.forEachChild(child => {
|
|
37
|
+
pending.push(child);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return ranges;
|
|
41
|
+
};
|
package/dist/v2-migration.d.ts
CHANGED
|
@@ -23,7 +23,45 @@ export interface LumenV2MigrationReport {
|
|
|
23
23
|
manualReview: LumenV2MigrationFinding[];
|
|
24
24
|
root: string;
|
|
25
25
|
}
|
|
26
|
+
interface ImportStatement {
|
|
27
|
+
clause: string;
|
|
28
|
+
end: number;
|
|
29
|
+
module: string;
|
|
30
|
+
quote: '\'' | '"';
|
|
31
|
+
semicolon: boolean;
|
|
32
|
+
start: number;
|
|
33
|
+
}
|
|
34
|
+
interface NamedImport {
|
|
35
|
+
imported: string;
|
|
36
|
+
local: string;
|
|
37
|
+
source: string;
|
|
38
|
+
typeOnly: boolean;
|
|
39
|
+
}
|
|
40
|
+
interface ParsedNamedImports {
|
|
41
|
+
close: number;
|
|
42
|
+
complete: boolean;
|
|
43
|
+
imports: NamedImport[];
|
|
44
|
+
open: number;
|
|
45
|
+
}
|
|
46
|
+
interface MarkupAttribute {
|
|
47
|
+
end: number;
|
|
48
|
+
name: string;
|
|
49
|
+
nameEnd: number;
|
|
50
|
+
nameStart: number;
|
|
51
|
+
start: number;
|
|
52
|
+
value: string | undefined;
|
|
53
|
+
valueKind: 'boolean' | 'expression' | 'literal';
|
|
54
|
+
}
|
|
55
|
+
export declare const findImportStatements: (source: string, module: string) => ImportStatement[];
|
|
56
|
+
export declare const parseNamedImports: (clause: string) => ParsedNamedImports | undefined;
|
|
57
|
+
export declare const findBalancedEnd: (source: string, start: number, opening: string, closing: string) => number;
|
|
58
|
+
export declare const parseMarkupAttributes: (source: string, start: number, end: number) => MarkupAttribute[];
|
|
59
|
+
export declare const findMarkupTagEnd: (source: string, start: number, rejectNestedTags?: boolean) => number;
|
|
60
|
+
export declare const getTagNameEnd: (source: string, start: number) => number;
|
|
61
|
+
export declare const getMarkupStart: (source: string, file: string) => number;
|
|
26
62
|
export declare const migrateLumenV2Source: (source: string, file?: string) => LumenV2SourceMigration;
|
|
63
|
+
export declare const discoverSourceFiles: (path: string, extensions?: ReadonlySet<string>) => Promise<string[]>;
|
|
27
64
|
export declare const migrateLumenV2: (options?: LumenV2MigrationOptions) => Promise<LumenV2MigrationReport>;
|
|
28
65
|
export declare const formatLumenV2Migration: (report: LumenV2MigrationReport) => string;
|
|
66
|
+
export {};
|
|
29
67
|
//# sourceMappingURL=v2-migration.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"v2-migration.d.ts","sourceRoot":"","sources":["../src/v2-migration.ts"],"names":[],"mappings":"AA4CA,MAAM,MAAM,oBAAoB,GAC5B,uBAAuB,GACzB,+BAA+B,GAC/B,sBAAsB,GACtB,2BAA2B,CAAA;AAE7B,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,oBAAoB,CAAA;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,uBAAuB,EAAE,CAAA;IAClC,YAAY,EAAE,uBAAuB,EAAE,CAAA;IACvC,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,EAAE,uBAAuB,EAAE,CAAA;IAClC,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,uBAAuB,EAAE,CAAA;IACvC,IAAI,EAAE,MAAM,CAAA;CACb;
|
|
1
|
+
{"version":3,"file":"v2-migration.d.ts","sourceRoot":"","sources":["../src/v2-migration.ts"],"names":[],"mappings":"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"}
|
package/dist/v2-migration.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readdir, readFile,
|
|
1
|
+
import { lstat, readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
2
|
import { extname, relative, resolve } from 'node:path';
|
|
3
3
|
// cspell:words swiftpm
|
|
4
4
|
const ASTRO_PACKAGE = '@santi020k/lumen-astro';
|
|
@@ -76,7 +76,7 @@ const createFinding = (source, file, index, kind, message) => ({
|
|
|
76
76
|
kind,
|
|
77
77
|
message
|
|
78
78
|
});
|
|
79
|
-
const findImportStatements = (source, module) => {
|
|
79
|
+
export const findImportStatements = (source, module) => {
|
|
80
80
|
const statements = [];
|
|
81
81
|
for (const quote of ['\'', '"']) {
|
|
82
82
|
const needle = `${quote}${module}${quote}`;
|
|
@@ -101,7 +101,7 @@ const findImportStatements = (source, module) => {
|
|
|
101
101
|
}
|
|
102
102
|
return statements.sort((left, right) => left.start - right.start);
|
|
103
103
|
};
|
|
104
|
-
const parseNamedImports = (clause) => {
|
|
104
|
+
export const parseNamedImports = (clause) => {
|
|
105
105
|
const open = clause.indexOf('{');
|
|
106
106
|
const close = clause.lastIndexOf('}');
|
|
107
107
|
if (open < 0 || close <= open)
|
|
@@ -136,7 +136,7 @@ const formatImport = (clause, statement) => `import ${clause} from ${statement.q
|
|
|
136
136
|
const applyEdits = (source, edits) => edits
|
|
137
137
|
.sort((left, right) => right.start - left.start)
|
|
138
138
|
.reduce((result, edit) => `${result.slice(0, edit.start)}${edit.replacement}${result.slice(edit.end)}`, source);
|
|
139
|
-
const findBalancedEnd = (source, start, opening, closing) => {
|
|
139
|
+
export const findBalancedEnd = (source, start, opening, closing) => {
|
|
140
140
|
let depth = 0;
|
|
141
141
|
let quote;
|
|
142
142
|
for (let index = start; index < source.length; index += 1) {
|
|
@@ -236,7 +236,7 @@ const parseMarkupAttribute = (source, start, end) => {
|
|
|
236
236
|
const valueStart = skipWhitespace(source, equalsStart + 1, end);
|
|
237
237
|
return parseMarkupAttributeValue(source, start, nameEnd, name, valueStart, end);
|
|
238
238
|
};
|
|
239
|
-
const parseMarkupAttributes = (source, start, end) => {
|
|
239
|
+
export const parseMarkupAttributes = (source, start, end) => {
|
|
240
240
|
const attributes = [];
|
|
241
241
|
let cursor = start;
|
|
242
242
|
while (cursor < end) {
|
|
@@ -255,7 +255,14 @@ const advanceQuotedSource = (character, quote) => ({
|
|
|
255
255
|
close: character === quote,
|
|
256
256
|
skip: character === '\\'
|
|
257
257
|
});
|
|
258
|
-
const
|
|
258
|
+
const getMarkupBoundary = (character, braceDepth, rejectNestedTags, index) => {
|
|
259
|
+
if (braceDepth !== 0)
|
|
260
|
+
return undefined;
|
|
261
|
+
if (character === '>')
|
|
262
|
+
return index;
|
|
263
|
+
return character === '<' && rejectNestedTags ? -1 : undefined;
|
|
264
|
+
};
|
|
265
|
+
export const findMarkupTagEnd = (source, start, rejectNestedTags = false) => {
|
|
259
266
|
let braceDepth = 0;
|
|
260
267
|
let quote;
|
|
261
268
|
for (let index = start; index < source.length; index += 1) {
|
|
@@ -274,8 +281,11 @@ const findMarkupTagEnd = (source, start) => {
|
|
|
274
281
|
braceDepth += 1;
|
|
275
282
|
else if (character === '}')
|
|
276
283
|
braceDepth = Math.max(0, braceDepth - 1);
|
|
277
|
-
else
|
|
278
|
-
|
|
284
|
+
else {
|
|
285
|
+
const boundary = getMarkupBoundary(character, braceDepth, rejectNestedTags, index);
|
|
286
|
+
if (boundary !== undefined)
|
|
287
|
+
return boundary;
|
|
288
|
+
}
|
|
279
289
|
}
|
|
280
290
|
return source.length;
|
|
281
291
|
};
|
|
@@ -359,7 +369,7 @@ const migrateRuntimeImports = (source, file) => {
|
|
|
359
369
|
}
|
|
360
370
|
return { changes, manualReview, source: applyEdits(source, edits) };
|
|
361
371
|
};
|
|
362
|
-
const getTagNameEnd = (source, start) => {
|
|
372
|
+
export const getTagNameEnd = (source, start) => {
|
|
363
373
|
let end = start;
|
|
364
374
|
while (/[\w:.-]/u.test(source[end] ?? ''))
|
|
365
375
|
end += 1;
|
|
@@ -400,7 +410,7 @@ const inspectVisualSize = (source, file, tagName, replacementName, attributes) =
|
|
|
400
410
|
review: createFinding(source, file, size.start, 'visual-size-alias-removal', message)
|
|
401
411
|
};
|
|
402
412
|
};
|
|
403
|
-
const getMarkupStart = (source, file) => {
|
|
413
|
+
export const getMarkupStart = (source, file) => {
|
|
404
414
|
if (!file.endsWith('.astro'))
|
|
405
415
|
return 0;
|
|
406
416
|
const opening = /^(?:\uFEFF)?\s*---\s*(?:\r?\n|$)/u.exec(source);
|
|
@@ -675,14 +685,16 @@ export const migrateLumenV2Source = (source, file = '<source>') => {
|
|
|
675
685
|
source: sonnerElements.source
|
|
676
686
|
};
|
|
677
687
|
};
|
|
678
|
-
const discoverSourceFiles = async (path) => {
|
|
679
|
-
const details = await
|
|
688
|
+
export const discoverSourceFiles = async (path, extensions = SOURCE_EXTENSIONS) => {
|
|
689
|
+
const details = await lstat(path);
|
|
690
|
+
if (details.isSymbolicLink())
|
|
691
|
+
return [];
|
|
680
692
|
if (details.isFile())
|
|
681
|
-
return
|
|
693
|
+
return extensions.has(extname(path)) ? [path] : [];
|
|
682
694
|
const entries = await readdir(path, { withFileTypes: true });
|
|
683
695
|
const nested = await Promise.all(entries
|
|
684
696
|
.filter(entry => !entry.isDirectory() || !IGNORED_DIRECTORIES.has(entry.name))
|
|
685
|
-
.map(entry => discoverSourceFiles(resolve(path, entry.name))));
|
|
697
|
+
.map(entry => discoverSourceFiles(resolve(path, entry.name), extensions)));
|
|
686
698
|
return nested.flat().sort();
|
|
687
699
|
};
|
|
688
700
|
export const migrateLumenV2 = async (options = {}) => {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export interface LumenV4MigrationFinding {
|
|
2
|
+
column: number;
|
|
3
|
+
file: string;
|
|
4
|
+
line: number;
|
|
5
|
+
message: string;
|
|
6
|
+
rule: string;
|
|
7
|
+
}
|
|
8
|
+
export interface LumenV4MigrationReport {
|
|
9
|
+
applied: boolean;
|
|
10
|
+
changedFiles: string[];
|
|
11
|
+
changes: LumenV4MigrationFinding[];
|
|
12
|
+
filesScanned: number;
|
|
13
|
+
manualReview: LumenV4MigrationFinding[];
|
|
14
|
+
packageVersions: Record<string, string>;
|
|
15
|
+
root: string;
|
|
16
|
+
targetVersion: string;
|
|
17
|
+
}
|
|
18
|
+
export declare const migrateLumenV4Source: (source: string, file?: string) => {
|
|
19
|
+
changes: LumenV4MigrationFinding[];
|
|
20
|
+
source: string;
|
|
21
|
+
};
|
|
22
|
+
export declare const migrateLumenV4: (options?: {
|
|
23
|
+
apply?: boolean | undefined;
|
|
24
|
+
cwd?: string | undefined;
|
|
25
|
+
}) => Promise<LumenV4MigrationReport>;
|
|
26
|
+
//# sourceMappingURL=v4-migration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"v4-migration.d.ts","sourceRoot":"","sources":["../src/v4-migration.ts"],"names":[],"mappings":"AAgBA,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAA;IAChB,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,OAAO,EAAE,uBAAuB,EAAE,CAAA;IAClC,YAAY,EAAE,MAAM,CAAA;IACpB,YAAY,EAAE,uBAAuB,EAAE,CAAA;IACvC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvC,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;CACtB;AAqKD,eAAO,MAAM,oBAAoB,GAAI,QAAQ,MAAM,EAAE,aAAiB,KAAG;IACvE,OAAO,EAAE,uBAAuB,EAAE,CAAA;IAClC,MAAM,EAAE,MAAM,CAAA;CAuCf,CAAA;AA+HD,eAAO,MAAM,cAAc,GACzB,UAAS;IAAE,KAAK,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAAO,KACtE,OAAO,CAAC,sBAAsB,CAwBhC,CAAA"}
|
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import { readdir, readFile, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
3
|
+
import { basename, extname, join, relative, resolve } from 'node:path';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
import { scriptRegexRanges } from './source-script-ranges.js';
|
|
6
|
+
const modules = new Map([
|
|
7
|
+
['@modelcontextprotocol/sdk/client/index.js', '@modelcontextprotocol/client'],
|
|
8
|
+
['@modelcontextprotocol/sdk/client/stdio.js', '@modelcontextprotocol/client/stdio'],
|
|
9
|
+
['@modelcontextprotocol/sdk/server/mcp.js', '@modelcontextprotocol/server'],
|
|
10
|
+
['@modelcontextprotocol/sdk/server/stdio.js', '@modelcontextprotocol/server/stdio']
|
|
11
|
+
]);
|
|
12
|
+
const sourceExtensions = new Set(['.astro', '.html', '.htm', '.js', '.jsx', '.mjs', '.ts', '.tsx', '.swift', '.kt', '.kts']);
|
|
13
|
+
const ignored = new Set(['.git', '.build', '.astro', '.next', '.expo', '.turbo', '.wrangler', '.swiftpm', 'node_modules', 'dist', 'build', 'coverage', 'Pods', 'DerivedData', 'vendor']);
|
|
14
|
+
const identifier = (character) => /[A-Za-z0-9_$]/u.test(character);
|
|
15
|
+
const stringToken = (source, start, quote) => {
|
|
16
|
+
let end = start + 1;
|
|
17
|
+
while (end < source.length && source[end] !== quote)
|
|
18
|
+
end += source[end] === '\\' ? 2 : 1;
|
|
19
|
+
end = Math.min(end + 1, source.length);
|
|
20
|
+
return { end, kind: 'string', start, value: source.slice(start + 1, end - 1) };
|
|
21
|
+
};
|
|
22
|
+
const commentAt = (source, start) => {
|
|
23
|
+
if (source.startsWith('//', start)) {
|
|
24
|
+
const end = source.indexOf('\n', start + 2);
|
|
25
|
+
return end < 0 ? source.length : end;
|
|
26
|
+
}
|
|
27
|
+
if (source.startsWith('/*', start)) {
|
|
28
|
+
const end = source.indexOf('*/', start + 2);
|
|
29
|
+
return end < 0 ? source.length : end + 2;
|
|
30
|
+
}
|
|
31
|
+
return undefined;
|
|
32
|
+
};
|
|
33
|
+
// Comments and complete string/template literals are consumed once. Never edit text examples.
|
|
34
|
+
const tokenAt = (source, start) => {
|
|
35
|
+
const character = source[start] ?? '';
|
|
36
|
+
if (/\s/u.test(character))
|
|
37
|
+
return start + 1;
|
|
38
|
+
const commentEnd = commentAt(source, start);
|
|
39
|
+
if (commentEnd !== undefined)
|
|
40
|
+
return commentEnd;
|
|
41
|
+
if (['"', '\'', '`'].includes(character))
|
|
42
|
+
return stringToken(source, start, character);
|
|
43
|
+
if (identifier(character)) {
|
|
44
|
+
let end = start + 1;
|
|
45
|
+
while (end < source.length && identifier(source[end] ?? ''))
|
|
46
|
+
end += 1;
|
|
47
|
+
return { end, kind: 'identifier', start, value: source.slice(start, end) };
|
|
48
|
+
}
|
|
49
|
+
return { end: start + 1, kind: 'punctuation', start, value: character };
|
|
50
|
+
};
|
|
51
|
+
const tokenize = (source, exclusions) => {
|
|
52
|
+
const tokens = [];
|
|
53
|
+
let cursor = 0;
|
|
54
|
+
while (cursor < source.length) {
|
|
55
|
+
const excludedEnd = exclusions.get(cursor);
|
|
56
|
+
if (excludedEnd !== undefined) {
|
|
57
|
+
cursor = excludedEnd;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const token = tokenAt(source, cursor);
|
|
61
|
+
if (typeof token === 'number')
|
|
62
|
+
cursor = token;
|
|
63
|
+
else {
|
|
64
|
+
tokens.push(token);
|
|
65
|
+
cursor = token.end;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return tokens;
|
|
69
|
+
};
|
|
70
|
+
const location = (source, index) => {
|
|
71
|
+
const prefix = source.slice(0, index);
|
|
72
|
+
return { column: index - prefix.lastIndexOf('\n'), line: prefix.split('\n').length };
|
|
73
|
+
};
|
|
74
|
+
const planImport = (source, token, state, startsLine) => {
|
|
75
|
+
if (token.value === 'import') {
|
|
76
|
+
state.inImport = startsLine;
|
|
77
|
+
state.afterFrom = false;
|
|
78
|
+
return undefined;
|
|
79
|
+
}
|
|
80
|
+
if (!state.inImport)
|
|
81
|
+
return undefined;
|
|
82
|
+
if ([';', '(', '='].includes(token.value)) {
|
|
83
|
+
state.inImport = false;
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
if (token.kind === 'identifier' && token.value === 'from') {
|
|
87
|
+
state.afterFrom = true;
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
if (token.kind !== 'string')
|
|
91
|
+
return undefined;
|
|
92
|
+
state.inImport = false;
|
|
93
|
+
const replacement = modules.get(token.value);
|
|
94
|
+
if (!state.afterFrom)
|
|
95
|
+
return undefined;
|
|
96
|
+
if (!replacement)
|
|
97
|
+
return undefined;
|
|
98
|
+
if (source[token.start] === '`')
|
|
99
|
+
return undefined;
|
|
100
|
+
return { end: token.end - 1, replacement, start: token.start + 1 };
|
|
101
|
+
};
|
|
102
|
+
const advancePosition = (source, end, position) => {
|
|
103
|
+
while (position.cursor < end) {
|
|
104
|
+
const character = source[position.cursor] ?? '';
|
|
105
|
+
if (character === '\n') {
|
|
106
|
+
position.line += 1;
|
|
107
|
+
position.column = 1;
|
|
108
|
+
position.blankPrefix = true;
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
position.column += 1;
|
|
112
|
+
if (!/\s/u.test(character))
|
|
113
|
+
position.blankPrefix = false;
|
|
114
|
+
}
|
|
115
|
+
position.cursor += 1;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
export const migrateLumenV4Source = (source, file = '<source>') => {
|
|
119
|
+
const exclusions = scriptRegexRanges(source, file);
|
|
120
|
+
if (!exclusions)
|
|
121
|
+
return { changes: [], source };
|
|
122
|
+
const edits = [];
|
|
123
|
+
const changes = [];
|
|
124
|
+
const state = { afterFrom: false, inImport: false };
|
|
125
|
+
const position = { blankPrefix: true, column: 1, cursor: 0, line: 1 };
|
|
126
|
+
for (const token of tokenize(source, exclusions)) {
|
|
127
|
+
advancePosition(source, token.start, position);
|
|
128
|
+
const edit = planImport(source, token, state, position.blankPrefix);
|
|
129
|
+
if (!edit)
|
|
130
|
+
continue;
|
|
131
|
+
edits.push(edit);
|
|
132
|
+
changes.push({
|
|
133
|
+
column: position.column,
|
|
134
|
+
line: position.line,
|
|
135
|
+
file,
|
|
136
|
+
message: `Replace ${token.value} with ${edit.replacement}; update SDK dependencies and rebuild together.`,
|
|
137
|
+
rule: 'embedded-mcp-sdk-v2'
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
let migrated = '';
|
|
141
|
+
let cursor = 0;
|
|
142
|
+
for (const edit of edits) {
|
|
143
|
+
migrated += source.slice(cursor, edit.start) + edit.replacement;
|
|
144
|
+
cursor = edit.end;
|
|
145
|
+
}
|
|
146
|
+
return { changes, source: migrated + source.slice(cursor) };
|
|
147
|
+
};
|
|
148
|
+
const isRecord = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
149
|
+
const strings = (value) => {
|
|
150
|
+
if (!Array.isArray(value) || !value.every((entry) => typeof entry === 'string'))
|
|
151
|
+
throw new Error('Invalid v4 migration string list.');
|
|
152
|
+
return value;
|
|
153
|
+
};
|
|
154
|
+
const loadRules = async () => {
|
|
155
|
+
const value = JSON.parse(await readFile(new URL('../v4-migration.json', import.meta.url), 'utf8'));
|
|
156
|
+
if (!isRecord(value) || typeof value.targetVersion !== 'string' || !Array.isArray(value.changes))
|
|
157
|
+
throw new Error('Invalid v4 migration contract.');
|
|
158
|
+
const rules = value.changes.map((entry) => {
|
|
159
|
+
if (!isRecord(entry) || typeof entry.id !== 'string' || typeof entry.migration !== 'string')
|
|
160
|
+
throw new Error('Invalid v4 migration rule.');
|
|
161
|
+
return {
|
|
162
|
+
id: entry.id,
|
|
163
|
+
migration: entry.migration,
|
|
164
|
+
packages: strings(entry.packages),
|
|
165
|
+
signals: strings(entry.signals)
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
return { rules, targetVersion: value.targetVersion };
|
|
169
|
+
};
|
|
170
|
+
const discover = async (directory) => {
|
|
171
|
+
const files = [];
|
|
172
|
+
for (const entry of await readdir(directory, { withFileTypes: true })) {
|
|
173
|
+
if (entry.isSymbolicLink())
|
|
174
|
+
continue;
|
|
175
|
+
const path = join(directory, entry.name);
|
|
176
|
+
if (entry.isDirectory() && !ignored.has(entry.name))
|
|
177
|
+
files.push(...await discover(path));
|
|
178
|
+
else if (entry.isFile() && (sourceExtensions.has(extname(path)) || entry.name === 'package.json'))
|
|
179
|
+
files.push(path);
|
|
180
|
+
}
|
|
181
|
+
return files.sort();
|
|
182
|
+
};
|
|
183
|
+
const resolveInstalled = async (path, name, range) => {
|
|
184
|
+
const require = createRequire(pathToFileURL(path));
|
|
185
|
+
try {
|
|
186
|
+
const installed = JSON.parse(await readFile(require.resolve(`${name}/package.json`), 'utf8'));
|
|
187
|
+
if (isRecord(installed) && typeof installed.version === 'string')
|
|
188
|
+
return installed.version;
|
|
189
|
+
throw new Error(`Invalid installed package metadata for ${name}.`);
|
|
190
|
+
}
|
|
191
|
+
catch (error) {
|
|
192
|
+
if (!isRecord(error) || !['MODULE_NOT_FOUND', 'ERR_PACKAGE_PATH_NOT_EXPORTED'].includes(String(error.code)))
|
|
193
|
+
throw error;
|
|
194
|
+
return `unresolved:${range}`;
|
|
195
|
+
}
|
|
196
|
+
};
|
|
197
|
+
const inventoryGroup = async (path, group) => {
|
|
198
|
+
const result = {};
|
|
199
|
+
if (!isRecord(group))
|
|
200
|
+
return result;
|
|
201
|
+
for (const [name, range] of Object.entries(group)) {
|
|
202
|
+
if (!name.startsWith('@santi020k/lumen') && !name.startsWith('@modelcontextprotocol/'))
|
|
203
|
+
continue;
|
|
204
|
+
if (typeof range !== 'string')
|
|
205
|
+
throw new Error(`Invalid dependency version for ${name}.`);
|
|
206
|
+
result[name] = await resolveInstalled(path, name, range);
|
|
207
|
+
}
|
|
208
|
+
return result;
|
|
209
|
+
};
|
|
210
|
+
const inventory = async (path) => {
|
|
211
|
+
const value = JSON.parse(await readFile(path, 'utf8'));
|
|
212
|
+
if (!isRecord(value))
|
|
213
|
+
throw new Error(`Invalid package manifest: ${path}`);
|
|
214
|
+
const result = {};
|
|
215
|
+
for (const group of [value.dependencies, value.devDependencies, value.peerDependencies]) {
|
|
216
|
+
for (const [name, version] of Object.entries(await inventoryGroup(path, group)))
|
|
217
|
+
result[name] = version;
|
|
218
|
+
}
|
|
219
|
+
return result;
|
|
220
|
+
};
|
|
221
|
+
const reviewSource = (source, file, rules) => {
|
|
222
|
+
const usesLumen = source.includes('lumen') || source.includes('LumenUI') || source.includes('Lumen');
|
|
223
|
+
return rules.flatMap(rule => {
|
|
224
|
+
if (!usesLumen && rule.id !== 'embedded-mcp-sdk-v2')
|
|
225
|
+
return [];
|
|
226
|
+
const signal = rule.signals.find(value => source.includes(value));
|
|
227
|
+
if (!signal)
|
|
228
|
+
return [];
|
|
229
|
+
return [{ ...location(source, source.indexOf(signal)), file, message: rule.migration, rule: rule.id }];
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
const migrateFile = async (path, rules, report) => {
|
|
233
|
+
report.filesScanned += 1;
|
|
234
|
+
const file = relative(report.root, path);
|
|
235
|
+
const source = await readFile(path, 'utf8');
|
|
236
|
+
const webCode = ['.ts', '.js', '.mjs'].includes(extname(path));
|
|
237
|
+
const migration = webCode ? migrateLumenV4Source(source, file) : { changes: [], source };
|
|
238
|
+
report.changes.push(...migration.changes);
|
|
239
|
+
report.manualReview.push(...reviewSource(source, file, rules));
|
|
240
|
+
if (migration.source === source)
|
|
241
|
+
return;
|
|
242
|
+
report.changedFiles.push(file);
|
|
243
|
+
if (!report.applied)
|
|
244
|
+
return;
|
|
245
|
+
if (await readFile(path, 'utf8') !== source)
|
|
246
|
+
throw new Error(`Source changed during migration: ${file}`);
|
|
247
|
+
await writeFile(path, migration.source, 'utf8');
|
|
248
|
+
};
|
|
249
|
+
export const migrateLumenV4 = async (options = {}) => {
|
|
250
|
+
const root = resolve(options.cwd ?? process.cwd());
|
|
251
|
+
const { rules, targetVersion } = await loadRules();
|
|
252
|
+
const report = {
|
|
253
|
+
applied: options.apply === true,
|
|
254
|
+
changedFiles: [],
|
|
255
|
+
changes: [],
|
|
256
|
+
filesScanned: 0,
|
|
257
|
+
manualReview: [],
|
|
258
|
+
packageVersions: {},
|
|
259
|
+
root,
|
|
260
|
+
targetVersion
|
|
261
|
+
};
|
|
262
|
+
for (const path of await discover(root)) {
|
|
263
|
+
if (basename(path) === 'package.json') {
|
|
264
|
+
for (const [name, version] of Object.entries(await inventory(path))) {
|
|
265
|
+
report.packageVersions[`${relative(root, path)}:${name}`] = version;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
else
|
|
269
|
+
await migrateFile(path, rules, report);
|
|
270
|
+
}
|
|
271
|
+
return report;
|
|
272
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface LumenMigrationDependencyOptions {
|
|
2
|
+
allowDirty?: boolean;
|
|
3
|
+
apply?: boolean;
|
|
4
|
+
dependencies?: boolean;
|
|
5
|
+
}
|
|
6
|
+
/** Dependency mutations precede source edits so rollout's dirty-worktree guard stays authoritative. */
|
|
7
|
+
export declare const applyLumenVersionMigrationDependencies: (root: string, targetVersion: string, options: LumenMigrationDependencyOptions) => Promise<import("./consumer-rollout.js").ConsumerRolloutReport>;
|
|
8
|
+
//# sourceMappingURL=version-migration-dependencies.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-migration-dependencies.d.ts","sourceRoot":"","sources":["../src/version-migration-dependencies.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,+BAA+B;IAC9C,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED,uGAAuG;AACvG,eAAO,MAAM,sCAAsC,GACjD,MAAM,MAAM,EACZ,eAAe,MAAM,EACrB,SAAS,+BAA+B,mEAQxC,CAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { runConsumerRollout } from './consumer-rollout.js';
|
|
2
|
+
/** Dependency mutations precede source edits so rollout's dirty-worktree guard stays authoritative. */
|
|
3
|
+
export const applyLumenVersionMigrationDependencies = (root, targetVersion, options) => runConsumerRollout({
|
|
4
|
+
allowDirty: options.allowDirty === true,
|
|
5
|
+
apply: options.apply === true,
|
|
6
|
+
repositories: [root],
|
|
7
|
+
targetVersion,
|
|
8
|
+
// Verify after source migration, through the consumer's normal completion gate.
|
|
9
|
+
verify: false
|
|
10
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { LumenMigrationVersion, LumenVersionSourceMigration } from './version-migration.js';
|
|
2
|
+
/** Assumes v3 input for v4. Filesystem apply uses a ledger to prevent repeated spacing rewrites. */
|
|
3
|
+
export declare const migrateLumenVersionSource: (source: string, file: string, version: LumenMigrationVersion) => LumenVersionSourceMigration;
|
|
4
|
+
//# sourceMappingURL=version-migration-source.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-migration-source.d.ts","sourceRoot":"","sources":["../src/version-migration-source.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,qBAAqB,EAAgC,2BAA2B,EAAE,MAAM,wBAAwB,CAAA;AA8V9H,oGAAoG;AACpG,eAAO,MAAM,yBAAyB,GACpC,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,SAAS,qBAAqB,KAC7B,2BA4BF,CAAA"}
|