Skip to content

migrate to null-safety codes and Flutter 3.3.0 #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
"typescript.tsc.autoDetect": "off",
"mochaExplorer.files": "**/*.test.ts",
"mochaExplorer.require": "ts-node/register",
"mochaExplorer.optsFile": "mocha.opts"
}
"mochaExplorer.optsFile": "mocha.opts",
"editor.formatOnSave": true
}
32 changes: 22 additions & 10 deletions src/generators/class-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -187,9 +187,9 @@ class ${rootWidget.controller}Base {
return `

class ${widgetName} extends StatelessWidget${mixinsCode} {
${rootWidget.params.filter(a => !!a.name).map(a => `final ${a.type ? a.type + ' ' : ''}${a.name}${a.value !== undefined ? ' = ' + a.value : ''};`).join('\n ')}
${rootWidget.params.filter(a => !!a.name).map(a => `final ${a.type ? (a.value === undefined && !a.required ? a.type + '? ' : a.type + ' ') : ''}${a.name}${a.value !== undefined ? ' = ' + a.value : ''};`).join('\n ')}
${widgetName}(${rootWidget.params.length ? '{': ''}
${rootWidget.params.map(a => `${a.required ? '@required ' : ''}${a.name ? `this.${a.name}` : `${(a.type ? a.type + ' ' : '')}${a.superParamName}`}`).join(',\n ')}
${rootWidget.params.map(a => `${a.required ? 'required ' : ''}${a.name ? `this.${a.name}` : `${(a.type ? a.type + ' ' : '')}${a.superParamName}`}`).join(',\n ')}
${rootWidget.params.length ? '}': ''});
${buildMethodContent}
}
Expand All @@ -198,18 +198,23 @@ class ${widgetName} extends StatelessWidget${mixinsCode} {

private createStatefulWidget(widgetName: string, mixinsCode: string, rootWidget: RootWidgetModel, controllers: VariableModel[], routeAware: boolean, routeAwareStateMethods: string, buildMethodContent: string, hasController: boolean, formControls: FormControlModel[]) {
const stateVarsDeclaration: string[] = [
...(hasController ? [`${rootWidget.controller} ctrl;`] : []),
...(hasController ? [`late ${rootWidget.controller} ctrl;`] : []),
...controllers.filter(a => !a.skipGenerate).map(a => a.isPrivate ? `final ${a.name} = new ${a.type}();` : `${a.type} ${a.name};`),
...rootWidget.providers.map(a => `${a.type} ${a.name};`),
...rootWidget.vars.map(a => `${a.type} ${a.name};`),
...(routeAware ? [`RouteObserver<Route> _routeObserver;`] : [])
...rootWidget.vars.map(a => `late ${a.type} ${a.name};`),
...(routeAware ? [`late RouteObserver<Route> _routeObserver;`] : [])
];
const stateVarsInit: string[] = [
...(hasController ? [`ctrl = new ${rootWidget.controller}();`] : []),
...(hasController ? rootWidget.params.filter(a => !!a.name).map(a => `ctrl._${a.name} = widget.${a.name};`) : []),
...controllers.filter(a => !a.isPrivate && !a.skipGenerate).map(a => `${hasController ? `ctrl._${a.name} = `: ''}${a.name} = ${a.value ? a.value : `new ${a.type}()`};`),
...rootWidget.vars.map(a => `${hasController ? `ctrl._${a.name} = `: ''}${a.name} = ${a.value};`),
...(hasController ? [`WidgetsBinding.instance?.addPostFrameCallback((_) => mounted ? ctrl.afterFirstBuild(context) : null);`] : [])
...(hasController ? [`WidgetsBinding.instance.addPostFrameCallback((_) => mounted ? ctrl.afterFirstBuild(context) : null);`] : [])
];
const stateVarsUpdate: string[] = [
...(hasController ? rootWidget.params.filter(a => !!a.name).map(a => `ctrl._${a.name} = widget.${a.name};`) : []),
...controllers.filter(a => !a.isPrivate && !a.skipGenerate).map(a => `${hasController ? `ctrl._${a.name} = `: ''}${a.name} = ${a.value ? a.value : `new ${a.type}()`};`),
...rootWidget.vars.map(a => `${hasController ? `ctrl._${a.name} = `: ''}${a.name} = ${a.value};`),
];
const superParams = rootWidget.params
.filter(a => a.superParamName)
Expand All @@ -220,9 +225,9 @@ class ${widgetName} extends StatelessWidget${mixinsCode} {
return `

class ${widgetName} extends StatefulWidget {
${rootWidget.params.filter(a => !!a.name).map(a => `final ${a.type ? a.type + ' ' : ''}${a.name};`).join('\n ')}
${rootWidget.params.filter(a => !!a.name).map(a => `final ${a.type ? (a.value === undefined && !a.required ? a.type + '? ' : a.type + ' ') : ''}${a.name};`).join('\n ')}
${widgetName}(${rootWidget.params.length ? '{': ''}
${rootWidget.params.map(a => `${a.required ? '@required ' : ''}${a.name ? `this.${a.name}` : `${(a.type ? a.type + ' ' : '')}${a.superParamName}`}${a.value !== undefined ? ' = ' + a.value : ''}`).join(',\n ')}
${rootWidget.params.map(a => `${a.required ? 'required ' : ''}${a.name ? `this.${a.name}` : `${(a.type ? a.type + ' ' : '')}${a.superParamName}`}${a.value !== undefined ? ' = ' + a.value : ''}`).join(',\n ')}
${rootWidget.params.length ? '}': ''})${superCtor};

@override
Expand All @@ -238,9 +243,14 @@ class _${widgetName}State extends State<${widgetName}>${mixinsCode} {
super.initState();${(stateVarsInit.length > 0 ? '\n ' : '') + stateVarsInit.join(`\n `)}
}

@override
void didUpdateWidget(${widgetName} oldWidget) {
super.didUpdateWidget(oldWidget);${(stateVarsUpdate.length > 0 ? '\n ' : '') + stateVarsUpdate.join(`\n `)}
}

@override
void didChangeDependencies() {
super.didChangeDependencies();${routeAware ? `\n _routeObserver = Provider.of<RouteObserver<Route>>(context)..subscribe(this, ModalRoute.of(context));` : ''
super.didChangeDependencies();${routeAware ? `\n _routeObserver = Provider.of<RouteObserver<Route>>(context)..subscribe(this, ModalRoute.of(context) as Route);` : ''
}${(rootWidget.providers.length ? '\n ' : '') + rootWidget.providers.map(a => `${hasController ? `ctrl._${a.name} = `: ''}${a.name} = Provider.of<${a.type}>(context);`).join('\n ')
}${hasController ? `\n ctrl._load(context);` : ''}
}
Expand All @@ -257,7 +267,9 @@ class _${widgetName}State extends State<${widgetName}>${mixinsCode} {

private createControllerVar(a: VariableModel): string {
a.type = a.type || 'var';
return `${a.type} _${a.name};\n ${a.type} get ${a.name} => _${a.name};`;
return ((a as any).required || a.value !== undefined) ?
`late ${a.type} _${a.name};\n ${a.type} get ${a.name} => _${a.name};` :
`${a.type}? _${a.name};\n ${a.type}? get ${a.name} => _${a.name};`;
}

generateControllerFile(fileName: string, rootWidget: RootWidgetModel): string {
Expand Down
29 changes: 20 additions & 9 deletions src/language-features/providers/fix_code_action_provider.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import * as vscode from "vscode";

import {
CancellationToken,
CodeAction,
Expand All @@ -12,10 +14,10 @@ import {
WorkspaceEdit,
commands,
} from 'vscode';
import { Location, SourceChange } from '../dart-ext-types';
import { getDartCodeIndex, getDartDocument } from '../utils';

import { RankedCodeActionProvider } from './ranking_code_action_provider';
import { getDartDocument } from '../utils';
import { SourceChange } from '../dart-ext-types';

export class FixCodeActionProvider implements RankedCodeActionProvider {
constructor(public readonly selector: DocumentSelector) { }
Expand All @@ -26,10 +28,13 @@ export class FixCodeActionProvider implements RankedCodeActionProvider {
providedCodeActionKinds: [CodeActionKind.QuickFix],
};

public async provideCodeActions(xmlDocument: TextDocument, xmlRange: Range, context: CodeActionContext, token: CancellationToken): Promise<CodeAction[] | undefined> {
const dartDocument = await getDartDocument(xmlDocument);
const location = ((context.diagnostics[0] || {}) as any).location as Location;
if (!location || location.offset === -1) {
public async provideCodeActions(xmlDocument: TextDocument, cursorRange: Range, context: CodeActionContext, token: CancellationToken): Promise<CodeAction[] | undefined> {
if (context.diagnostics.length < 1) {
return undefined;
}

const xmlRange = context.diagnostics[0].range;
if (!xmlRange || xmlRange.start == null) {
return undefined;
}

Expand All @@ -38,8 +43,14 @@ export class FixCodeActionProvider implements RankedCodeActionProvider {
}

try {
const rangeStart = dartDocument.positionAt(location.offset);
let results: (Command | CodeAction)[] = await commands.executeCommand('vscode.executeCodeActionProvider', dartDocument.uri, new Range(rangeStart, rangeStart.translate({ characterDelta: 10 })));
const dartDocument = await getDartDocument(xmlDocument);
const dartOffset = getDartCodeIndex(xmlDocument, xmlRange.start, dartDocument, xmlRange);
const rangeEnd = dartOffset != -1 ? dartDocument.positionAt(dartOffset) : null;

const dartRange = dartOffset != -1 ? new Range(rangeEnd.translate({ characterDelta: -(xmlRange.end.character - xmlRange.start.character) }), rangeEnd) :
new Range(dartDocument.positionAt(0), dartDocument.positionAt(dartDocument.getText().length - 1)) ;

let results: (Command | CodeAction)[] = await commands.executeCommand('vscode.executeCodeActionProvider', dartDocument.uri, dartRange );
return results.map(a => this.buildCodeAction(xmlDocument, a));
}
catch (e) {
Expand All @@ -50,7 +61,7 @@ export class FixCodeActionProvider implements RankedCodeActionProvider {

private buildCodeAction(document: TextDocument, command: Command | CodeAction): CodeAction {
const innerCommand = command.command as any;
const title = innerCommand && innerCommand.title ? innerCommand.title : command.title;
const title = command.title ? command.title : innerCommand.title;
if (!title || !title.startsWith('Import library')) {
return null;
}
Expand Down
13 changes: 10 additions & 3 deletions src/language-features/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { TextDocument, workspace, Uri, Position, Range } from "vscode";
import * as path from "path";
import { isAttribute, getXPath, isTagName, isClosingTagName } from "./xmlUtils";

import { Position, Range, TextDocument, Uri, workspace } from "vscode";
import { getXPath, isAttribute, isClosingTagName, isTagName } from "./xmlUtils";

import { Location } from "./dart-ext-types";

export const isWin = /^win/.test(process.platform);
Expand Down Expand Up @@ -159,6 +161,11 @@ export function getDartCodeIndex(xmlDocument: TextDocument, xmlPosition: Positio
dartOffset = classIndex;
}
}
} else {
if (wordRange) {
const code = xmlDocument.getText(wordRange);
dartOffset = dart.indexOf(code);
}
}

return dartOffset;
Expand Down Expand Up @@ -220,4 +227,4 @@ export function getXmlCodeWordLocation(xmlDocument: TextDocument, dart: string,

const startPos = xmlDocument.positionAt(xmlOffset + 1);
return new Range(startPos, startPos.translate(0, word.length));
}
}
36 changes: 19 additions & 17 deletions src/manager.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,27 @@
import * as fs from 'fs';
import * as mkdirp from 'mkdirp';
import * as path from "path";
import * as vscode from "vscode";
import * as mkdirp from 'mkdirp';
import * as fs from 'fs';
import { denodeify } from 'q';
import { WidgetResolver } from "./resolvers/widget-resolver";
import { ParseXml } from "./parser/parser";
import { PropertyHandlerProvider } from "./providers/property-handler-provider";
import { WrapperPropertyHandler } from "./property-handlers/wrapper-property";

import { Config, ConfigValueTransformer } from "./models/config";
import { IValueTransformer, ValueTransformersProvider } from "./providers/value-transformers-provider";
import { registerBuiltInPropertyHandlers, registerBuiltInValueTransformers } from "./builtin-handlers";

import { ChildWrapperPropertyHandler } from "./property-handlers/child-wrapper-property";
import { ValueTransformersProvider, IValueTransformer } from "./providers/value-transformers-provider";
import { EnumValueTransformer } from "./value-transformers/enum";
import { EdgeInsetsValueTransformer } from "./value-transformers/edge-insets";
import { ClassCodeGenerator } from "./generators/class-generator";
import { ColorValueTransformer } from "./value-transformers/color";
import { EdgeInsetsValueTransformer } from "./value-transformers/edge-insets";
import { EnumValueTransformer } from "./value-transformers/enum";
import { LocalizationGenerator } from "./generators/localization-generator";
import { ClassCodeGenerator } from "./generators/class-generator";
import { ParseXml } from "./parser/parser";
import { PipeValueResolver } from "./resolvers/pipe-value-resolver";
import { PropertyHandlerProvider } from "./providers/property-handler-provider";
import { PropertyResolver } from "./resolvers/property-resolver";
import { WidgetCodeGenerator } from "./generators/widget-generator";
import { WidgetResolver } from "./resolvers/widget-resolver";
import { WrapperPropertyHandler } from "./property-handlers/wrapper-property";
import { denodeify } from 'q';
import { insertAutoCloseTag } from "./autoclose/autoclose";
import { Config, ConfigValueTransformer } from "./models/config";
import { registerBuiltInValueTransformers, registerBuiltInPropertyHandlers } from "./builtin-handlers";
import { PropertyResolver } from "./resolvers/property-resolver";
import { PipeValueResolver } from "./resolvers/pipe-value-resolver";

const mkdir = denodeify(mkdirp);
const writeFile = denodeify(fs.writeFile);
Expand Down Expand Up @@ -171,11 +173,11 @@ export default class Manager {
layoutDart = this.classGenerator.generate(rootWidget, controllerFileName);
}
catch (ex) {
const diagnostic = this.getExceptionDiagnostics(ex.message);
const diagnostic = this.getExceptionDiagnostics((ex as any).message);
if (diagnostic) {
this.diagnostics.set(fileUri, [diagnostic]);
}
const customMessage = this.getCustomErrorMessage(ex.message);
const customMessage = this.getCustomErrorMessage((ex as any).message);
if (customMessage) {
vscode.window.showErrorMessage(customMessage);
this.output.appendLine(customMessage);
Expand Down
8 changes: 5 additions & 3 deletions src/property-handlers/builder.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { CustomPropertyHandler, PropertyResolveResult, WidgetResolveResult } from "../providers/property-handler-provider";
import * as parseXml from '../parser/types';
import { WidgetModel, ExtraDataModel, AttributeModel, PropertyModel, AttributeInfo } from '../models/models';

import { AttributeInfo, AttributeModel, ExtraDataModel, PropertyModel, WidgetModel } from '../models/models';
import { CustomPropertyHandler, PropertyResolveResult, WidgetResolveResult } from "../providers/property-handler-provider";
import { extractForLoopParams, makeTabs, sortProperties, spaceAfter } from "../utils";

import { PropertyResolver } from "../resolvers/property-resolver";

export class BuilderHandler extends CustomPropertyHandler {
Expand Down Expand Up @@ -199,7 +201,7 @@ export class BuilderHandler extends CustomPropertyHandler {
// if (hasItemList && (!data.params || data.indexName)) {
if (hasItemList) {
code += `
${tabs} final ${spaceAfter(data.typeName)}${data.itemName} = ${data.listValueVariableName} == null || ${data.listValueVariableName}.length <= ${indexName} || ${data.listValueVariableName}.length == 0 ? null : ${data.listValueVariableName}[${indexName}];`;
${tabs} final ${spaceAfter(data.typeName)}${data.itemName} = (${data.listValueVariableName} as dynamic) == null || ${data.listValueVariableName}.length <= ${indexName} || ${data.listValueVariableName}.length == 0 ? [] : ${data.listValueVariableName}[${indexName}];`;
}

if (ifWidgets && ifWidgets.length) {
Expand Down
13 changes: 7 additions & 6 deletions src/property-handlers/wrapper-animation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { WidgetModel, PropertyModel, VariableModel, AttributeInfo } from '../models/models';
import { AttributeInfo, PropertyModel, VariableModel, WidgetModel } from '../models/models';

import { PropertyResolver } from '../resolvers/property-resolver';
import { WrapperPropertyHandler } from "./wrapper-property";
import { makeTabs } from '../utils';
import { PropertyResolver } from '../resolvers/property-resolver';

export class WrapperAnimationHandler extends WrapperPropertyHandler {
isElement = true;
Expand Down Expand Up @@ -41,7 +42,7 @@ export class WrapperAnimationHandler extends WrapperPropertyHandler {
value:`GlobalKey<AnimationBuilderState>()`
});
vars.push({
name:`AnimationBuilderStateMixin get ${animationControllerName} => _${animationControllerName}Key.currentState;`,
name:`AnimationBuilderStateMixin get ${animationControllerName} => _${animationControllerName}Key.currentState as AnimationBuilderStateMixin;`,
type: '',
value:``
});
Expand Down Expand Up @@ -69,7 +70,7 @@ export class WrapperAnimationHandler extends WrapperPropertyHandler {
extraData: {
parameters: [
{ name: 'animations', type: 'Map<String, Animation>' },
{ name: `child`, type: 'Widget' }
{ name: `child`, type: 'Widget?' }
],
addReturn: true
}
Expand Down Expand Up @@ -124,7 +125,7 @@ export class WrapperAnimationHandler extends WrapperPropertyHandler {
const values = tweens.map(t => {
return {
propertyName: t.property,
propertyValue: `animations["${t.property}"]${isTransitionWidget ? '' : '.value'}`
propertyValue: `animations["${t.property}"]${isTransitionWidget ? '' : '!.value'}`
};
});

Expand Down Expand Up @@ -180,4 +181,4 @@ export class WrapperAnimationHandler extends WrapperPropertyHandler {
.join(',\n');
return `${tabs}tweenMap: {\n${code}\n${tabs}}`;
}
}
}
14 changes: 8 additions & 6 deletions src/resolvers/pipe-value-resolver.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { scan } from "../parser/parser";
import * as parseXml from '../parser/types';
import * as Syntax from '../parser/syntax';
import { WidgetModel, ExtraDataModel } from "../models/models";
import { makeVariableName, makePipeUniqueName } from "../utils";
import * as parseXml from '../parser/types';

import { ExtraDataModel, WidgetModel } from "../models/models";
import { makePipeUniqueName, makeVariableName } from "../utils";

import { scan } from "../parser/parser";

export class PipeValueResolver {

Expand Down Expand Up @@ -103,7 +105,7 @@ export class PipeValueResolver {
extraData: {
parameters: [
{ name: 'context', type: 'BuildContext' },
{ name: `${snapshotVarName}`, type: '' }
{ name: `${snapshotVarName}`, type: 'dynamic' }
],
logic: [
...(addLocalVar ? [`final ${resultVarName} = ${snapshotVarName}.data;`] : []),
Expand Down Expand Up @@ -315,4 +317,4 @@ export class PipeValueResolver {
const matches = scan({ xml: args, pos: 0 }, Syntax.Global.PipeArgs);
return matches;
}
}
}